Расширенный $! в zsh
May. 4th, 2016 12:28 pm![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
Возникла задача получения pid последнего форкнутого процесса.
Проблема: если форкается труба (
Рещение влоб:
Как временное решение подойдёт, но если ядро рандомизирует выдачу pidов, то работать не будет.
Решение через хеш jobstates:
jobstates содержит индексированные состояния таблицы заданий:
Поля:
Пример использования:

Проблема: если форкается труба (
cmd1 | cmd2 | cmd3
), то $!
возвращает pid последнего процесса в трубе, а хотелось бы получить pid первого (в общем случае любого) для последующего отстрела, если он зависнет (e.g. ssh host cat big-file | sha1sum
).Рещение влоб:
$[$!-1], $[$!-2]
для доступа к cmd2, cmd1 etc.Как временное решение подойдёт, но если ядро рандомизирует выдачу pidов, то работать не будет.
Решение через хеш jobstates:
1 # function get-last-pipe-pids () {
2 emulate -L zsh
3 setopt extendedglob
4
5 local -a ary; local elm
6 for elm in ${(v)jobstates}; do
7 ary=( ${(@s.:.)elm} )
8 [[ ${ary[2]} == "+" ]] && break
9 ary=()
10 done
11
12 [[ $#ary == 0 ]] && return 1
13 if [[ $# == 0 ]]; then
14 print -l ${${ary[3,-1]}%=*}
15 else
16 print ${${${ary[3,-1]}%=*}[$1]}
17 fi
18 return
19
20 # }
jobstates содержит индексированные состояния таблицы заданий:
# sleep 60 | cat | cat &
[1] 20831 20832 20833
# sleep 60 | cat | cat &
[2] 20835 20836 20837
# print -l ${(v)jobstates}
running:-:20831=running:20832=running:20833=running
running:+:20835=running:20836=running:20837=running
Поля:
- Статус задания (running, suspended, done)
- Обозначение задания ("+" -- текущее, "-" -- предидущее, пустое поля для всех остальных)
- Список pidов процессов в трубе с их состоянием
- Строки 2-3 -- стандартный заголовок для zsh-скриптов
- Строка 5 -- заводим локальные переменные
- Строки 6-10 -- ищем в значениях (v) jobstates текущее задание (последнее из запущеных) и складываем поля, поделённые по ":" в массив ary
- Строка 12 -- если ничего нет, то выходим с кодом ошибки
- Строка 14 -- если аргументов нет, то печатаем pidы всех процессов (первые два поля -- состояние процесса и его обозначение нам не нужны, а состояние конкретного процесса удаляется с помощью квалификатора
%=*
) - Строка 16 -- если есть аргумент то это номер монады в трубе, и печатаем только её pid.
Пример использования:
# sleep 60 | cat | cat &
[1] 21191 21192 21193
# sleep 60 | cat | cat &
[2] 21195 21196 21197
# get-last-pipe-pids
21195
21196
21197
# get-last-pipe-pids 1
21195
