Я, должно быть, что-то упускаю:
#!/bin/bash
timeout 5 sleep 10 &
parent_pid=$( ps --pid $! -o ppid --no-headers )
timeout_pid=$( pgrep --parent $parent_pid timeout )
wait $timeout_pid
echo "exit code: $?"
Вызовите скрипт wait-pid
и запустите:
$ ./wait-pid
exit code: 124
как я и ожидал, процесс timeout
завершается sleep
и возвращается код 124 wait
.
Но если я добавлю конвейер к исходной команде:
timeout 5 sleep 10 | cat &
parent_pid=$( ps --pid $! -o ppid --no-headers )
timeout_pid=$( pgrep --parent $parent_pid timeout )
wait $timeout_pid
echo "exit code: $?"
теперь я получаю:
$ ./wait-pid
exit code: 0
Не должен wait
по-прежнему возвращать код завершения процесса, которого он ожидает: timeout
. Так что не должен ли код завершения по-прежнему быть 124.
Это касается bash версии 4.4.20(1).
решение1
Я получил ответ от супер-знающего Грега Вуледжа в списке рассылки bash. Ключевой элемент:
Команда wait работает только с прямыми дочерними процессами оболочки, также известными как "асинхронные команды". В случае, если ваша асинхронная команда является конвейером, мы возвращаемся к исходному набору функций sh. Статус выхода вашей асинхронной команды совпадает со статусом выхода последней команды в конвейере, а статусы выхода других команд просто отбрасываются.
Вот почему я не получаю код выхода, timeout
когда он находится в конвейере.
Способ получить желаемое поведение — использовать временный файл для захвата кодов выхода из асинхронного кода. Что-то вроде:
{
timeout 5 sleep 10 | cat
echo "${PIPESTATUS[@]}" > "$tempfile"
} &
wait