В то время как большинство оболочек поддерживают синхронизацию внешних и встроенных команд, zsh не поддерживает синхронизацию для встроенных команд.
Если вам нужно получить результат времени, вы можете позвонить
time /bin/true
или отправьте отчет об ошибке людям из zsh.
С новой информацией все выглядит иначе.
Сложные команды синхронизации работают только в том случае, если time
является зарезервированным словом в оболочке.
Таким образом, у вас есть два ограничивающих фактора
оболочка должна иметь возможность синхронизировать встроенные команды
оболочка должна реализовать time
как зарезервированное слово, улучшающее синтаксис оболочки
Это сокращает список потенциальных оболочек до:
bosh bash mksh ksh
Для встроенных команд оболочка должна знать, как измерять собственное время.
Для сложных команд оболочка должна реализовать time
внутри интерпретатора.
Когда фоновое задание представляет собой конвейер в форме cmd1 | cmd2
, оно по-прежнему остается одним фоновым заданием. Невозможно узнать, когда начнется cmd1
.
Каждый &
создает одно фоновое задание. Как только cmd &
возвращается, оболочка знает о том, что фоновое задание:cmd & jobs
перечисляет cmd
. cmd & pid=$!
задает pid
идентификатор процесса, который выполняет cmd
.
Конвейер cmd1 | cmd2
создает еще два подпроцесса :один для запуска cmd1
и один для запуска cmd2
. Оба процесса являются потомками подпроцесса, выполняющего фоновое задание. Вот как выглядит дерево процессов дляbash -c '{ sleep 123 | sleep 456; } & jobs -p; sleep 789'
:
PID PPID CMD
268 265 | \_ bash -c { sleep 123 | sleep 456; } & sleep 789
269 268 | \_ bash -c { sleep 123 | sleep 456; } & sleep 789
270 269 | | \_ sleep 123
271 269 | | \_ sleep 456
272 268 | \_ sleep 789
268 — это исходный процесс bash. 269 — это фоновое задание, которое jobs -p
печатает. 270 и 271 — это левая -и правая -стороны канала, оба дочерние по отношению к основному процессу фонового задания (269 ).
Версия bash, которую я тестировал с (5.0.17 в Linux ), оптимизирует cmd1 | cmd2 &
без фигурных скобок. В этом случае левая -сторона конвейера выполняется в том же процессе, что и фоновое задание :
PID PPID CMD
392 389 | \_ bash -c sleep 123 | sleep 456 & jobs -p; sleep 789
393 392 | \_ sleep 123
394 392 | \_ sleep 456
395 392 | \_ sleep 789
Нельзя полагаться на то, что это поведение будет стабильным в разных версиях bash или, возможно, даже в разных платформах, дистрибутивах, версиях libc и т. д.
jobs -p %cmd1
ищет задание, код которого начинается с cmd1
. Он находит cmd1 | cmd2
. jobs -p %?cmd2
находит ту же работу¹. Невозможно получить доступ к идентификаторам процессов, запущенных cmd1
и cmd2
, через встроенные -функции bash.
Если вам нужно точно знать, что cmd1
запущен, используйте подстановку процесса.
cmd1 >(cmd2)
Вы не узнаете, когда cmd2
начинается и заканчивается.
Если вам нужно знать, когда cmd1
и cmd2
начинаются и заканчиваются, вам нужно сделать их обе заданиями и заставить их обмениваться данными через именованный канал.
tmp=$(mktemp -d) # Remove this in cleanup code
mkfifo "$tmp/pipe"
cmd1 >"$tmp/pipe" & pid1=$!
cmd2 <"$tmp/pipe" & pid2=$!
…
Команда jobs
не очень полезна в сценариях. Используйте $!
, чтобы запомнить PID фоновых заданий.
¹ Или, по крайней мере, должен. Моя версия жалуется на неоднозначную спецификацию работы,что должно быть ошибкой, поскольку он говорит об этом, несмотря на то, что существует только одна работа.