Тройник сбрасывает статус выхода всегда 0
У меня есть такой короткий сценарий:
#!/bin/bash
<some_process> | tee -a /tmp/some.log &
wait $(pidof <some_process_name>)
echo $?
Результат всегда равен 0, независимо от состояния выхода some_process.
Я знаю, что PIPESTATUS можно использовать здесь, но почему тройник ломается wait
?
3 ответа
Ну, это то, что, по какой-то особой причине, документы не упоминают. Код, однако, делает:
int wait_for (pid) { /*...*/
/* If this child is part of a job, then we are really waiting for the
job to finish. Otherwise, we are waiting for the child to finish. [...] */
if (job == NO_JOB)
job = find_job (pid, 0, NULL);
Таким образом, он на самом деле ждет всей работы, которая, как мы знаем, обычно выдает статус выхода последней команды в цепочке.
Усугублять проблему, $PIPESTATUS
может использоваться только с последней командой переднего плана.
Вы можете, однако, использовать $PIPESTATUS
в подзадаче, как это:
(<some_process> | tee -a /tmp/some.log; exit ${PIPESTATUS[0]}) &
# somewhere down the line:
wait %%<some_process>
Хитрость здесь заключается в использовании $PIPESTATUS
но также wait -n
:
Проверьте этот пример:
#!/bin/bash
# start background task
(sleep 5 | false | tee -a /tmp/some.log ; exit ${PIPESTATUS[1]}) &
# foreground code comes here
echo "foo"
# wait for background task to finish
wait -n
echo $?
Причина, по которой вы всегда получаете статус выхода 0
то, что возвращаемое состояние выхода - это состояние последней команды в конвейере, которая tee
, Используя канал, вы устраняете нормальное обнаружение состояния выхода <some_command>
,
Со страницы руководства bash:
Состояние возврата конвейера - это состояние выхода последней команды, если не включена опция pipefail. Если pipefail включен, статус возврата конвейера - это значение последней (самой правой) команды для выхода с ненулевым статусом или ноль, если все команды завершаются успешно.
Итак... Следующее может быть тем, что вы хотите:
#!/usr/bin/env bash
set -o pipefail
<some_command> | tee -a /tmp/some.log &
wait %1
echo $?