Bash: Trap ERR не работает при использовании оператора pipe

Я пытаюсь регистрировать все, что выходит из stdout и stderr, в файл журнала и по-прежнему сохранять консоль. Для этого я просто добавил: |& tee -a log_file.log к каждой команде.
Тем не менее, я также хочу запустить пользовательскую команду, если во время выполнения сценария возникнет какая-либо ошибка. Для этого я добавил в начало скрипта следующее: trap "echo Non-zero exit code detected" ERR.
Проблема заключается в использовании оператора канала, эхо в ловушке больше не выполняется.

Скрипт 1, без трубы:

$cat test.sh
#!/bin/bash

trap "echo Non-zero exit code detected!" ERR

function fail_please()
{
    echo "Returning non-zero exit code!"
    return 1
}

fail_please 

Выход 1:

$ ./test.sh 
Returning non-zero exit code!
Non-zero exit code detected!

Скрипт 2 с трубкой:

$ cat test.sh
#!/bin/bash

trap "echo Non-zero exit code detected!" ERR

function fail_please()
{
    echo "Returning non-zero exit code!"
    return 1
}

fail_please |& tee log_file.log 

Выход 2:

$ ./test.sh
Returning non-zero exit code!
$ cat log_file.log 
Returning non-zero exit code!

На выходе 2 сообщение «Обнаружен ненулевой код выхода!» пропал, отсутствует. Есть идеи, почему? Спасибо!


person cristiprg    schedule 18.12.2014    source источник
comment
Ловушка ERR срабатывает для простых команд, конвейер не является простой командой. Это может сработать для результата всего конвейера (я не уверен), и вы можете получить что-то более близкое к тому, что хотите, установив pipefail. Это одна из причин, по которой люди часто не рекомендуют использовать set -e, поскольку в нем есть такие удивительные детали.   -  person Etan Reisner    schedule 18.12.2014
comment
Спасибо! Я добавил set -o pipefail, и это сработало. Однако я не совсем понял, почему set -e не рекомендуется. Есть ли другие предостережения? Кроме того, добавьте ответ, чтобы принять его.   -  person cristiprg    schedule 18.12.2014
comment
У set -e есть аналогичные предостережения относительно вашей ERR ловушки. Он не срабатывает во всех ожидаемых ситуациях. И некоторые из этих ситуаций не связаны с вашим рабочим кодом.   -  person Etan Reisner    schedule 18.12.2014
comment
Чтобы уточнить, в сценарии 2, установив pipefail, код возврата канала по-прежнему равен 0 (потому что tee возвращает 0), но он позволяет моей ловушке ERR срабатывать в случае сбоя первой команды. Это верно?   -  person cristiprg    schedule 18.12.2014
comment
Я только что добавил к моему ответу комментарий о том, почему pipefail работает, но да, он устанавливает возврат к статусу выхода последней неудачной команды вместо того, чтобы всегда быть статусом выхода последней команды в конвейере.   -  person Etan Reisner    schedule 18.12.2014


Ответы (1)


Ловушка ERR срабатывает для «простых команд», конвейер не является простой командой.

Это может сработать для результата всего конвейера (я не уверен), и вы можете получить что-то более близкое к тому, что хотите, установив pipefail.

(Примечание: это одна из причин, по которой люди часто не рекомендуют использовать set -e, поскольку в нем есть такие удивительные детали.)

Причина, по которой pipefail работает, заключается в том, что обычно статус возврата конвейера - это возврат последней команды, но с pipefail он становится статусом возврата последней неудачной команды.

Статус возврата конвейера - это статус выхода последней команды, если не включена опция pipefail. Если включен pipefail, статус возврата конвейера - это значение последней (самой правой) команды для выхода с ненулевым статусом или ноль, если все команды завершаются успешно.

person Etan Reisner    schedule 18.12.2014