it-roy-ru.com

Отмена сценария оболочки, если какая-либо команда возвращает ненулевое значение?

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

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

например.

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

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

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

set -e

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

Смотрите man-страница bash (1) внутренней команды "set" для более подробной информации.

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

664
Ville Laurikari

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

Имейте в виду, что иногда 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 
set -o pipefail
 
 ./ configure | tee configure.log 
 make 
181
leonbloy

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

dosomething1 || exit 1

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

dosomething || true

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

74
Zan Lynx

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

27
fholo

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

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

12
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
10
Mark Edgar
#!/bin/bash -e

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

3
Baligh Uddin

Выражение как

dosomething1 && dosomething2 && dosomething3

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

cat nosuchfile && echo "done"
echo $?
1
3
gabor