Подтвердить что ты не робот

Почему флаг bash -e не работает, когда подоболочка терпит неудачу?

Я немного смущен. Моя цель здесь состоит в том, чтобы выход bash script с ненулевым кодом выхода, когда какая-либо из команд в script завершается с ошибкой. Используя флаг -e, я предположил, что это будет так, даже при использовании подоболочек. Ниже приведен упрощенный пример:

#!/bin/bash -e

(false)

echo $?
echo "Line reached!"

Вот результат при запуске:

[$]>Tests/Exec/continuous-integration.sh 
1
Line reached!

Bash версия: 3.2.25 на CentOS

4b9b3361

Ответ 1

Похоже, что это связано с вашей версией bash. На машинах, к которым у меня есть доступ, bash версия 3.1.17 и 3.2.39 демонстрирует это поведение, bash 4.1.5 не делает.

Хотя это немного уродливо, решение, работающее в обеих версиях, может быть примерно таким:

#!/bin/bash -e

(false) || exit $?

echo $?
echo "Line reached!"

В исходном журнале изменений bash есть некоторые примечания, связанные с ошибками с опцией set -e.

Ответ 2

Я видел это поведение в версии bash версии 3.2.51 как на SuSE 11.3, так и на Mac OS до El Capitan. bash 3.2.57 на El Capitan имеет "правильное" поведение, например, bash 4.

Однако обходное решение, предложенное выше, добавив "|| exit $?" после закрытия закрывающего пассажа, побеждает намерение флага -e независимо от версии bash. От человека bash:

-e Выйти немедленно, если вышла простая команда (см. SHELL GRAMMAR выше) с ненулевым статусом. Оболочка не выходит, если команда, которая не работает, часть списка команд сразу после некоторого времени или пока ключевое слово, часть теста в выражении if, часть && или || список,...

Подглазу, а затем "|| exit $?" видимо, считается списком команд; и флаг bash -e не будет применяться к любой команде внутри подоболочки. Попробуйте:

$ set -e
$ ( echo before the error; false; echo after the error, status $?; ) || echo after the subshell, status $?
before the error
after the error, status 1
$

Поскольку за подоболочкой следует ||, выполняется "echo after the error", даже с set -e. Мало того, подоболочка выходит из 0, потому что это "эхо" бежало. Итак, "|| exit $?" даже не запускает "выход". Наверное, не то, что мы хотели!

Насколько я знаю, следующая формула совместима с версиями bash, соблюдают ли они bash -e после подоболочки или нет. Он даже ведет себя корректно, если флаг -e имеет значение reset:

Добавьте следующую строку сразу после закрывающей круглой скобки каждой подоболочки в bash script:

case $?/$- in ( 0/* ) ;; ( */*e* ) exit $? ;; esac # honor bash -e flag when subshell returns