Прерывание сценария оболочки, если какая-либо команда возвращает ненулевое значение?
У меня есть сценарий оболочки Bash, который вызывает ряд команд. Я хотел бы, чтобы скрипт оболочки автоматически выходил с возвращаемым значением 1, если какая-либо из команд возвращает ненулевое значение.
Возможно ли это без явной проверки результата каждой команды?
например
dosomething1
if [[ $? -ne 0 ]]; then
exit 1
fi
dosomething2
if [[ $? -ne 0 ]]; then
exit 1
fi
10 ответов
Добавьте это в начало сценария:
set -e
Это приведет к немедленному завершению работы оболочки, если простая команда завершится с ненулевым значением выхода. Простая команда - это любая команда, не являющаяся частью теста if, while или before, или частью && или || список.
Смотрите страницу руководства bash(1) во внутренней команде set для более подробной информации.
Я лично запускаю почти все сценарии оболочки с помощью команды "set -e". Это действительно раздражает иметь сценарий упорно продолжать, когда что-то не в середине и разбивает предположения для остальной части скрипта.
Добавить к принятому ответу:
Имейте в виду, что set -e
иногда не достаточно, особенно если у вас есть трубы.
Например, предположим, у вас есть этот скрипт
#!/bin/bash
set -e
./configure > configure.log
make
... который работает как ожидалось: ошибка в configure
прерывает выполнение.
Завтра вы делаете, казалось бы, тривиальные изменения:
#!/bin/bash
set -e
./configure | tee configure.log
make
... и теперь это не работает. Это объясняется здесь, и предоставляется обходной путь (только Bash):
#! / Bin/ Баш установить -е set -o pipefail./configure | tee configure.log делать
Операторы if в вашем примере не нужны. Просто сделайте это так:
dosomething1 || exit 1
Если вы воспользуетесь советами Вилле Лаурикари и используйте set -e
тогда для некоторых команд вам может понадобиться использовать это:
dosomething || true
|| true
заставит командный конвейер иметь true
возвращаемое значение, даже если команда терпит неудачу, поэтому -e
опция не убьет скрипт.
Если у вас есть очистка, которую вы должны сделать при выходе, вы также можете использовать 'trap' с псевдосигналом ERR. Это работает так же, как захват INT или любого другого сигнала; bash выдает ERR, если какая-либо команда завершается с ненулевым значением:
# Create the trap with
# trap COMMAND SIGNAME [SIGNAME2 SIGNAME3...]
trap "rm -f /tmp/$MYTMPFILE; exit 1" ERR INT TERM
command1
command2
command3
# Partially turn off the trap.
trap - ERR
# Now a control-C will still cause cleanup, but
# a nonzero exit code won't:
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 error handling:
# exit on command failure
set -e
# keep track of the last executed command
trap 'LAST_COMMAND=$CURRENT_COMMAND; CURRENT_COMMAND=$BASH_COMMAND' DEBUG
# on error: print the failed command
trap 'ERROR_CODE=$?; FAILED_COMMAND=$LAST_COMMAND; tput setaf 1; echo "ERROR: command \"$FAILED_COMMAND\" failed with exit code $ERROR_CODE"; put sgr0;' ERR INT TERM
Выражение как
dosomething1 && dosomething2 && dosomething3
остановит обработку, когда одна из команд вернется с ненулевым значением. Например, следующая команда никогда не напечатает "done":
cat nosuchfile && echo "done"
echo $?
1
Просто добавлю еще один для справки, поскольку у Марка Эдгарса был дополнительный вопрос, и вот еще один пример, который затрагивает общую тему:
[[ `cmd` ]] && echo success_else_silence
который так же, как cmd || exit errcode
как кто-то показал.
например. Я хочу убедиться, что раздел отключен, если смонтирован:
[[ `mount | grep /dev/sda1` ]] && umount /dev/sda1