Прерывание оболочки 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