Прерывание скрипта оболочки при возвращении любой команды ненулевого значения
У меня есть Bash-скрипт, который выполняет несколько команд. Я хотел бы, чтобы скрипт автоматически завершался с кодом возврата 1, если любая из команд возвращает ненулевое значение.
Есть ли способ сделать это без явной проверки результата каждой команды?
Например, вместо следующего кода:
dosomething1
if [[ $? -ne 0 ]]; then
exit 1
fi
dosomething2
if [[ $? -ne 0 ]]; then
exit 1
fi
Я хотел бы узнать, можно ли упростить этот процесс.
5 ответ(ов)
Условные операторы if
в вашем примере не нужны. Просто сделайте это так:
dosomething1 || exit 1
Если вы последуете совету Ville Laurikari и используете set -e
, то для некоторых команд вам может понадобиться использовать следующую конструкцию:
dosomething || true
Использование || true
позволит команде вернуть значение true
, даже если сама команда завершится с ошибкой, благодаря чему опция -e
не приведет к остановке скрипта.
Если вам нужно выполнить очистку при выходе из скрипта, вы можете использовать команду trap
с псевдосигналом ERR
. Это работает так же, как и ловля других сигналов, таких как INT
; в bash генерируется сигнал ERR
, если любая команда заканчивается с ненулевым кодом возврата:
# Устанавливаем ловушку с
# trap COMMAND SIGNAME [SIGNAME2 SIGNAME3...]
trap "rm -f /tmp/$MYTMPFILE; exit 1" ERR INT TERM
command1
command2
command3
# Частично отключаем ловушку.
trap - ERR
# Теперь прерывание с помощью Ctrl+C все еще вызовет очистку,
# но ненужный ненулевой код возврата не вызовет:
ps aux | grep blahblahblah
Кроме того, особенно если вы используете set -e
, вы можете установить ловушку на сигнал EXIT
; ваша ловушка будет выполнена при любом выходе из скрипта, включая нормальное завершение, прерывания или выход, вызванный опцией -e
и т.д.
Переменная $?
редко требуется. Псевдо-идиома command; if [ $? -eq 0 ]; then X; fi
всегда должна быть записана в виде if command; then X; fi
.
Случаи, когда $?
необходимо использовать, возникают, если нужно проверить его на соответствие нескольким значениям:
command
case $? in
(0) X;;
(1) Y;;
(2) Z;;
esac
Или когда $?
нужно переиспользовать или каким-либо образом обработать:
if command; then
echo "command successful" >&2
else
ret=$?
echo "command failed with exit code $ret" >&2
exit $ret
fi
Запустите его с параметром -e
или добавьте set -e
в начало скрипта.
Также обратите внимание на set -u
.
Этот скрипт обрабатывает ошибки так, что при возникновении проблемы он выводит сообщение об ошибке красным цветом и завершает выполнение.
Добавьте следующий код в начало вашего bash-скрипта:
# Обработка ошибок в BASH:
# завершить выполнение при неудачном выполнении команды
set -e
# отслеживать последнюю выполненную команду
trap 'LAST_COMMAND=$CURRENT_COMMAND; CURRENT_COMMAND=$BASH_COMMAND' DEBUG
# при ошибке: вывести неудавшуюся команду
trap 'ERROR_CODE=$?; FAILED_COMMAND=$LAST_COMMAND; tput setaf 1; echo "ERROR: команда \"$FAILED_COMMAND\" завершилась с кодом $ERROR_CODE"; tput sgr0;' ERR INT TERM
Этот код обеспечивает автоматическую остановку скрипта, если какая-либо команда возвращает ненулевой код завершения, а также выводит информацию об ошибке, что может быть полезно для отладки.
Linux: Копирование и создание директории назначения, если она не существует
Что означает "2>&1"?
Как запросить ввод Yes/No/Cancel в скрипте оболочки Linux?
Как сделать паузу в shell-скрипте на одну секунду перед продолжением?
Как использовать 'grep' для непрерывного потока?