ожидание процесса в конвейере возвращает неправильный код выхода

ожидание процесса в конвейере возвращает неправильный код выхода

Я, должно быть, что-то упускаю:

#!/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

Связанный контент