Прерывание сценария оболочки, если какая-либо команда возвращает ненулевое значение? - PullRequest
383 голосов
/ 04 мая 2009

У меня есть сценарий оболочки Bash, который вызывает несколько команд. Я хотел бы, чтобы скрипт оболочки автоматически завершал работу с возвращаемым значением 1, если какая-либо из команд возвращает ненулевое значение.

Возможно ли это без явной проверки результата каждой команды?

например.

dosomething1
if [[ $? -ne 0 ]]; then
    exit 1
fi

dosomething2
if [[ $? -ne 0 ]]; then
    exit 1
fi

Ответы [ 9 ]

665 голосов
/ 04 мая 2009

Добавьте это в начало скрипта:

set -e

Это приведет к немедленному завершению оболочки при выходе из простой команды с ненулевым значением выхода. Простая команда - это любая команда, не являющаяся частью теста if, while или before, или частью && или || список.

Подробнее см. Справочную страницу bash (1) внутренней команды "set".

Лично я запускаю почти все сценарии оболочки с помощью команды "set -e". Это действительно раздражает иметь сценарий упорно продолжать, когда что-то не в середине и разбивает предположения для остальной части скрипта.

181 голосов
/ 03 декабря 2010

Добавить к принятому ответу:

Имейте в виду, что set -e иногда недостаточно, особенно если у вас есть трубы.

Например, предположим, у вас есть этот скрипт

#!/bin/bash
set -e 
./configure  > configure.log
make

... что работает как ожидалось: ошибка в configure прерывает выполнение.

Завтра вы сделаете, казалось бы, тривиальное изменение:

#!/bin/bash
set -e 
./configure  | tee configure.log
make

... и теперь это не работает. Это объясняется здесь , и предоставляется обходной путь (только для Bash):

#!/bin/bash
set -e 
<b>set -o pipefail</b>

./configure  | tee configure.log
make
74 голосов
/ 04 мая 2009

Операторы if в вашем примере не нужны. Просто сделай это так:

dosomething1 || exit 1

Если вы прислушиваетесь к совету Вилле Лаурикари и используете set -e, то для некоторых команд вам может понадобиться:

dosomething || true

|| true заставит конвейер команд иметь возвращаемое значение true, даже если команда не выполнена, поэтому опция -e не будет уничтожать сценарий.

27 голосов
/ 08 мая 2009

Если у вас есть очистка, которую вы должны сделать на выходе, вы также можете использовать '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, и т. д.

12 голосов
/ 04 мая 2009

Запустите его с -e или set -e вверху.

Также посмотрите на set -u.

10 голосов
/ 16 декабря 2009

Переменная $? требуется редко. Псевдо-идиома 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
3 голосов
/ 24 июля 2017
#!/bin/bash -e

должно хватить.

3 голосов
/ 04 мая 2009

Выражение типа

dosomething1 && dosomething2 && dosomething3

остановит обработку, когда одна из команд вернется с ненулевым значением. Например, следующая команда никогда не напечатает «done»:

cat nosuchfile && echo "done"
echo $?
1
0 голосов
/ 16 сентября 2012

просто добавляю еще один для справки, поскольку у Марка Эдгарса был дополнительный вопрос, и вот еще один пример, который затрагивает тему в целом:

[[ `cmd` ]] && echo success_else_silence

, что совпадает с cmd || exit errcode, как кто-то показал.

например. Я хочу убедиться, что раздел отключен, если смонтирован:

[[ `mount | grep /dev/sda1` ]] && umount /dev/sda1 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...