Прерывание оболочки script, если какая-либо команда возвращает ненулевое значение?
У меня есть Bash shell script, который вызывает несколько команд.
Я хотел бы, чтобы оболочка script автоматически выходила с возвратным значением 1, если какая-либо из команд возвращает ненулевое значение.
Возможно ли это без явной проверки результата каждой команды?
например.
dosomething1
if [[ $? -ne 0 ]]; then
exit 1
fi
dosomething2
if [[ $? -ne 0 ]]; then
exit 1
fi
Ответы
Ответ 1
Добавьте это в начало сценария:
set -e
Это приведет к немедленному завершению работы оболочки при выходе из простой команды с ненулевым значением выхода. Простая команда - это любая команда, не являющаяся частью команды if, while или before, или частью && или || список.
Для получения дополнительной информации см. справочную страницу bash (1) внутренней команды "set".
Я лично запускаю почти все сценарии оболочки с помощью "set -e". Это действительно раздражает иметь сценарий упорно продолжать, когда что-то не в середине и разбивает предположения для остальной части скрипта.
Ответ 2
Добавить к принятому ответу:
Помните, что иногда set -e
недостаточно, особенно если у вас есть pipes.
Например, предположим, что у вас есть этот скрипт
#!/bin/bash
set -e
./configure > configure.log
make
... что работает как ожидалось: ошибка в configure
прерывает выполнение.
Завтра вы делаете, казалось бы, тривиальное изменение:
#!/bin/bash
set -e
./configure | tee configure.log
make
... и теперь это не работает. Это объясняется здесь, и предоставляется обходной путь (только для Bash):
#!/bin/bash
set -e
set -o pipefail
./configure | tee configure.log
make
Ответ 3
Операторы if в вашем примере не нужны. Просто сделайте это так:
dosomething1 || exit 1
Если вы берете совет Ville Laurikari и используете set -e
, то для некоторых команд вам может понадобиться использовать это:
dosomething || true
|| true
приведет к тому, что конвейер команды получит возвращаемое значение true
, даже если команда завершилась неудачей, поэтому параметр -e
не будет убивать script.
Ответ 4
Если у вас есть очистка, которую вы должны выполнить при выходе, вы также можете использовать "ловушку" с 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; тогда ваша ловушка будет выполнена, когда script выйдет по какой-либо причине, включая нормальный конец, прерывания, выход, вызванный параметром -e и т.д.
Ответ 5
Запустите его с помощью -e
или set -e
вверху.
Также смотрите set -u
.
Ответ 6
Переменная $?
редко требуется. Псевдо-идиома 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
Ответ 7
Выражение вроде
dosomething1 && dosomething2 && dosomething3
прекратит обработку, когда одна из команд вернется с ненулевым значением. Например, следующая команда никогда не будет печатать "done":
cat nosuchfile && echo "done"
echo $?
1
Ответ 8
#!/bin/bash -e
должно быть достаточно.
Ответ 9
просто бросает в другой для справки, так как был добавлен дополнительный вопрос для ввода Mark Edgars, и вот еще один пример и касается темы в целом:
[[ `cmd` ]] && echo success_else_silence
что совпадает с cmd || exit errcode
, как показал кто-то.
например. Я хочу, чтобы раздел был отключен, если он установлен:
[[ `mount | grep /dev/sda1` ]] && umount /dev/sda1