Вихід із сценарію про помилку


141

Я будую сценарій оболонки, який має таку 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

...

Я хочу, щоб виконання сценарію закінчилося після відображення повідомлення про помилку. Як я можу це зробити?

Відповіді:


137

Шукаєте exit?

Це найкращий путівник по башу. 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 .
Призупинено до подальшого повідомлення.

Ці посилання Баша - ДУЖЕ! BashFAQ краще позиціонувати як BashRecipes.
Піт Елвін

337

Якщо ви введете 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 / ... - використання пастка «error_handler» ERR. Навіть якщо це пастка!
Бондолін

3
часто використання -xпрапора з -eпрапором достатньо сліду, де ваша програма знаходиться на виході. Це означає, що користувач сценарію також є розробником.
Алекс

Приємно, але я думаю, що ОП потребував виходу із сценарію із визначеного виключення.
vdegenne

42

Якщо ви хочете , щоб мати можливість обробляти помилку замість того , щоб сліпо виходу, замість того , щоб використовувати set -e, використовувати 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.


8

Ось як це зробити:

#!/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 *** 
************
'

Чому СПОСОБ зроблено повідомлення stderr?
MattBianco

1
Це звичайна практика, тому ви можете передавати свій вихід сценарію в stdout, щоб інший процес міг отримати його, не маючи інформаційних повідомлень посередині.
суперкобра

2
Напевно, однаково поширена практика трактувати що-небудь на stderr як ознаку проблем.
MattBianco

1
У минулому "set -e" завжди працював для мене, але сьогодні ввечері я зіткнувся з ситуацією на зображенні Alcker Linux Docker, де це не мало ефекту. Це рішення спрацювало для мене і повернуло мене на завдання. Цінується.
синтезаторпатель

@supercobra Загальна практика? Де?
Thorbjørn Ravn Andersen

-8

exit 1це все, що вам потрібно. Код 1повернення, тож ви можете змінити його, якщо хочете, скажімо, 1означати успішний запуск та -1означає провал або щось подібне.


13
У Unix успіх завжди дорівнює 0. Це може допомогти при використанні testабо &&або ||.
mouviciel

5
Щоб розширити коментар mouviciel: у скриптах оболонки 0 завжди означає успіх, а 1 - 255 означає збій. -1 знаходиться поза діапазоном (і часто матиме такий же ефект, як і 255, тому збій, як 1).
Жил 'ТАК - перестань бути злим'

@mouviciel, @Gilles: Дякую за додаткову інформацію. Минув час, як я займався басом.
DGH

Це поганий приклад використання зворотного коду, інакше це буде чудовою відповіддю.
Бред Кох

1
Окрім помилкового рекомендування 1 для успіху, -1 неможливо (вихідні коди не підписані).
трійчатка
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.