Тройник сбрасывает статус выхода всегда 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 $?
Другие вопросы по тегам