Один из моментов, пропущенных в существующих ответах, - это показать, как наследовать сообщения об ошибках. Оболочка bash
предоставляет одну такую опцию для использования set
-E
Если установлено, любая ловушка на ERR
наследуется функциями оболочки, подстановками команд и командами, выполняемыми в среде подоболочки. Ловушка ERR
обычно не наследуется в таких случаях.
Ответ Адама Розенфилда Рекомендация использовать set -e
в некоторых случаях верна, но имеет свои потенциальные ловушки. См. GreyCat's BashFAQ - 105 - Почему set -e (или -o errexit, или trap ERR) не выполняет то, что я ожидал?
В соответствии с инструкцией set -e выходит
если простой коммандекс с ненулевым статусом. Оболочка не завершает работу, если сбойная команда является частью списка команд, следующего сразу за ключевым словом while
или until
, частью test in a if statement
, часть списка &&
или ||
, кроме команды, следующей за final && or ||
, any command in a pipeline but the last
или если возвращаемое значение команды инвертируется с помощью !
".
, что означает, set -e
не работает в следующих простых случаях (подробные объяснения можно найти в вики)
Использование арифметического оператора let
или $((..))
(bash
4.1 и далее) для увеличения значения переменной как
#!/usr/bin/env bash
set -e
i=0
let i++ # or ((i++)) on bash 4.1 or later
echo "i is $i"
Если команда-нарушитель , а не часть последней команды, выполненной с помощью &&
или ||
. Например, приведенная ниже ловушка не сработает, когда ожидается
#!/usr/bin/env bash
set -e
test -d nosuchdir && echo no dir
echo survived
При неправильном использовании в операторе if
as код завершения оператора if
является кодом завершения последней выполненной команды. В приведенном ниже примере последней выполненной командой была echo
, которая не сработала бы в ловушке, даже если test -d
не удалось
#!/usr/bin/env bash
set -e
f() { if test -d nosuchdir; then echo no dir; fi; }
f
echo survived
При использовании с подстановкой команд они игнорируются, если inherit_errexit
не установлено с bash
4.4
#!/usr/bin/env bash
set -e
foo=$(expr 1-1; true)
echo survived
, когда вы используете команды, которые выглядят как назначения, но не такие, как export
, declare
, typeset
или local
. Здесь вызов функции f
будет , а не завершится, так как local
сместил код ошибки, который был установлен ранее.
set -e
f() { local var=$(somecommand that fails); }
g() { local var; var=$(somecommand that fails); }
При использовании в конвейере, и команда-нарушитель является , а не частью последней команды. Например, команда ниже все равно будет проходить. Один из вариантов - включить pipefail
, возвращая код завершения первого неудачного процесса:
set -e
somecommand that fails | cat -
echo survived
Идеальная рекомендация - , а не , использовать set -e
и использовать вместо этого собственную версию проверки ошибок. Дополнительная информация о реализации пользовательской обработки ошибок в одном из моих ответов на Поднять ошибку в скрипте Bash