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