Выход из сценария при ошибке

146

Я создаю сценарий оболочки, который имеет такую ifфункцию:

if jarsigner -verbose -keystore $keyst -keystore $pass $jar_file $kalias
then
    echo $jar_file signed sucessfully
else
    echo ERROR: Failed to sign $jar_file. Please recheck the variables
fi

...

Я хочу, чтобы выполнение сценария завершилось после отображения сообщения об ошибке. Как я могу это сделать?

Натан Кампос
источник

Ответы:

142

Ты ищешь exit?

Это лучшее руководство по bash. http://tldp.org/LDP/abs/html/

В контексте:

if jarsigner -verbose -keystore $keyst -keystore $pass $jar_file $kalias
then
    echo $jar_file signed sucessfully
else
    echo ERROR: Failed to sign $jar_file. Please recheck the variables 1>&2
    exit 1 # terminate and indicate error
fi

...
Байрон Уитлок
источник
5
Если вам нравится ABS, вам понравятся BashGuide , BashFAQ и BashPitfalls .
Приостановлено до дальнейшего уведомления.
Эти ссылки на Bash УДИВИТЕЛЬНЫ! BashFAQ лучше было бы позиционировать как BashRecipes.
Пит Элвин
343

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

Преимущество этого подхода в том, что он автоматический: вы не рискуете забыть обработать случай ошибки.

Команды, статус которых проверяется условным выражением (например if, &&или ||), не завершают сценарий (в противном случае условное выражение было бы бессмысленным). Идиома для случайных команд, сбой которых не имеет значения command-that-may-fail || true. Вы также можете set -eотключить часть скрипта с помощью set +e.

Жиль: "ТАК, перестань быть злым"
источник
3
Согласно mywiki.wooledge.org/BashFAQ/105, эта функция всегда была непонятной и запутанной в определении того, какие коды ошибок команд вызывают автоматический выход. Более того, «правила меняются от одной версии Bash к другой, поскольку Bash пытается отследить чрезвычайно скользкое определение этой« функции »в POSIX». Я согласен с @Dennis Williamson и принятым ответом stackoverflow.com/questions/19622198/… - используйте trap 'error_handler' ERR. Даже если это ловушка!
Bondolin
3
часто использования -xфлага с -eфлагом достаточно для отслеживания того, где ваша программа находится на выходе. Это означает, что пользователь сценария также является разработчиком.
Alexander Oh
Хорошо, но я думаю, что OP нужно было выйти из сценария из самоопределяемого исключения.
vdegenne
44

Если вы хотите иметь возможность обрабатывать ошибку вместо слепого выхода, вместо использования set -eиспользуйте a trapв ERRпсевдосигнале.

#!/bin/bash
f () {
    errorCode=$? # save the exit code as the first thing done in the trap function
    echo "error $errorCode"
    echo "the command executing at the time of the error was"
    echo "$BASH_COMMAND"
    echo "on line ${BASH_LINENO[0]}"
    # do some error handling, cleanup, logging, notification
    # $BASH_COMMAND contains the command that was being executed at the time of the trap
    # ${BASH_LINENO[0]} contains the line number in the script of that command
    # exit the script or return to try again, etc.
    exit $errorCode  # or use some other value or do return instead
}
trap f ERR
# do some stuff
false # returns 1 so it triggers the trap
# maybe do some other stuff

Можно настроить другие ловушки для обработки других сигналов, включая обычные сигналы Unix, а также другие псевдосигналы Bash RETURNи DEBUG.

Приостановлено до дальнейшего уведомления.
источник
9

Вот как это сделать:

#!/bin/sh

abort()
{
    echo >&2 '
***************
*** ABORTED ***
***************
'
    echo "An error occurred. Exiting..." >&2
    exit 1
}

trap 'abort' 0

set -e

# Add your script below....
# If an error occurs, the abort() function will be called.
#----------------------------------------------------------
# ===> Your script goes here
# Done!
trap : 0

echo >&2 '
************
*** DONE *** 
************
'
суперкобра
источник
Почему сообщение DONE для stderr?
MattBianco
1
Это обычная практика, поэтому вы можете направить вывод своего скрипта в stdout, чтобы другой процесс мог получить его, не имея информационных сообщений в середине.
supercobra
2
Вероятно, столь же распространенной практикой является трактовка чего-либо на stderr как признака проблемы.
MattBianco
1
В прошлом «set -e» всегда работал у меня, но сегодня вечером я столкнулся с ситуацией в образе Alpine Linux Docker, где он не оказал никакого действия. Это решение сработало для меня и вернуло меня к выполнению поставленной задачи. Очень признателен.
synthesizerpatel
@supercobra Обычная практика? Куда?
Торбьёрн Равн Андерсен
-8

exit 1это все, что тебе нужно. Это 1код возврата, поэтому вы можете изменить его, если хотите, например, 1чтобы он означал успешный запуск -1или сбой или что-то в этом роде.

DGH
источник
14
В unix успех всегда равен 0. Это может помочь при использовании testили &&или ||.
Mouviciel 07
5
Чтобы расширить комментарий mouviciel: в сценариях оболочки 0 всегда означает успех, а от 1 до 255 означает неудачу. -1 находится за пределами допустимого диапазона (и часто будет иметь тот же эффект, что и 255, поэтому ошибка, как 1).
Жиль 'SO- перестань быть злым'
@mouviciel, @Gilles: Спасибо за дополнительную информацию. Прошло много времени с тех пор, как я имел дело с bash.
DGH
Это плохой пример использования кода возврата, иначе это был бы отличный ответ.
Брэд Кох
1
В дополнение к неправильной рекомендации 1 для успеха, -1 невозможен (коды выхода беззнаковые).
tripleee