Я пишу сценарий на Bash для проверки кода. Тем не менее, кажется глупым запускать тесты, если компиляция кода не удалась, и в этом случае я просто прерву тесты.
Есть ли способ, которым я могу сделать это, не оборачивая весь скрипт внутри цикла while и не используя разрывы? Что-то вроде Дун Дун Дун Гото?
1
последовательно. Если сценарий предназначен для запуска другим сценарием, вы можете определить свой собственный набор кодов состояния с определенным значением. Например,1
== тесты не пройдены,2
== компиляция не удалась. Если сценарий является частью чего-то другого, вам может потребоваться настроить коды в соответствии с используемыми там практиками. Например, когда часть набора тестов запускается automake, код77
используется для обозначения пропущенного теста.exit #
команду в функцию, а не в скрипт. (В этом случае используйтеreturn #
вместо этого.)exit 0
выйдите из сценария и вернет 0 (сообщая другим сценариям, которые могли бы использовать результат этого сценария, он успешно)Используйте set -e
Сценарий завершится после первой неудачной строки (возвращает ненулевой код завершения). В этом случае command-that-fails2 не будет выполняться.
Если бы вы проверяли статус возврата каждой отдельной команды, ваш скрипт выглядел бы так:
С set -e это будет выглядеть так:
Любая неудачная команда приведет к сбою всего сценария и вернет состояние выхода, которое вы можете проверить с помощью $? , Если ваш сценарий очень длинный или вы создаете много материала, он будет довольно уродливым, если вы будете добавлять проверки статуса возврата везде.
источник
set -e
вас еще можно сделать некоторые команды выхода с ошибками без остановки сценария:command 2>&1 || echo $?
.set -e
прервет сценарий, если структура конвейера или команды вернет ненулевое значение. Напримерfoo || bar
, потерпит неудачу, только если обаfoo
иbar
вернут ненулевое значение. Обычно хорошо написанный сценарий bash будет работать, если вы добавляетеset -e
в начале, а дополнение работает как автоматическая проверка работоспособности: прервите сценарий, если что-то пойдет не так.set -o pipefail
параметр.set -e
был бы просто идиоматический код безmake || exit $?
.set -u
. Посмотрите на неофициальный Баш строгого режима :set -euo pipefail
.Один парень из SysOps однажды научил меня технике Трехпалого Когтя:
Эти функции * ОС NIX и оболочка устойчивы. Поместите их в начало вашего сценария (bash или иным образом),
try()
вашего утверждения и кода.объяснение
(основываясь на комментариях летающих овец ).
yell
: напечатать имя скрипта и все аргументы дляstderr
:$0
путь к сценарию;$*
все аргументы.>&2
означает>
перенаправление стандартного вывода на & pipe2
. труба1
была быstdout
сама собой.die
делает то же самоеyell
, но выходит с состоянием выхода, отличным от 0 , что означает «сбой».try
использует||
(логическое значениеOR
), которое оценивает правую сторону только в случае сбоя левой.$@
это все аргументы опять, но разные .источник
$0
это путь к сценарию.$*
все аргументы.>&2
означает «>
перенаправить стандартный поток на&
канал2
». труба 1 была бы самой stdout. поэтому yell префиксирует все аргументы с именем скрипта и печатает в stderr. die делает то же самое, что и yell , но выходит со статусом выхода не равным 0, что означает «сбой». try использует логическое значение or||
, которое оценивает правую сторону только в том случае, если левая сторона не вышла из строя.$@
это все аргументы опять, но разные . надеюсь, что все объясняетdie() { yell "$1"; exit $2; }
чтобы вы могли передать сообщение и код выхода с помощьюdie "divide by zero" 115
.yell
иdie
. Однакоtry
не так уж и много. Можете ли вы привести пример его использования?Если вы будете вызывать скрипт с помощью
source
, вы можете использоватьreturn <x>
где<x>
будет статус завершения скрипта (используйте ненулевое значение для ошибки или false). Но если вы вызываете исполняемый скрипт (т. Е. Непосредственно с его именем файла), оператор return приведет к жалобе (сообщение об ошибке «return: может только« вернуться »из функции или скрипта с источником»).Если
exit <x>
вместо этого используется, когда сценарий вызываетсяsource
, это приведет к выходу из оболочки, которая запустила сценарий, но исполняемый сценарий просто завершится, как и ожидалось.Чтобы обработать любой случай в одном и том же сценарии, вы можете использовать
Это будет обрабатывать любой вызов может быть подходящим. Это предполагает, что вы будете использовать это утверждение на верхнем уровне скрипта. Я бы посоветовал не выходить из скрипта непосредственно из функции.
Примечание:
<x>
предполагается, что это просто число.источник
Я часто включаю функцию run () для обработки ошибок. Каждый вызов, который я хочу сделать, передается этой функции, поэтому весь сценарий завершается, когда происходит сбой. Преимущество этого по сравнению с решением set -e состоит в том, что сценарий не завершает работу без вывода сообщений при сбое строки и может сказать вам, в чем проблема. В следующем примере 3-я строка не выполняется, потому что сценарий завершается при вызове false.
источник
set -e option
. Тогда команда, так как с аргументами, я использовал одиночные кавычки , чтобы избежать проблем Баш нравится так:runTry 'mysqldump $DB_PASS --user="$DB_USER" --host="$BV_DB_HOST" --triggers --routines --events --single-transaction --verbose $DB_SCHEMA $tables -r $BACKUP_DIR/$tables$BACKUP_FILE_NAME'
. Обратите внимание, что я изменил название функции на runTry.eval
потенциально опасно, если вы принимаете произвольный ввод, но в остальном это выглядит довольно хорошо.Вместо
if
конструкции вы можете использовать оценку короткого замыкания :Обратите внимание на пару круглых скобок, которые необходимы из-за приоритета оператора чередования.
$?
это специальная переменная, установленная для выхода из кода последней вызванной команды.источник
command -that --fails || exit $?
это работает без скобок, чтоecho $[4/0]
заставляет нас нуждаться в них?echo $[4/0] || exit $?
) bash никогда не выполнитecho
, не говоря уже о подчинении||
.У меня тот же вопрос, но я не могу его задать, потому что это будет дубликат.
Принятый ответ с использованием exit не работает, когда скрипт немного сложнее. Если вы используете фоновый процесс для проверки условия, выход завершает работу только этого процесса, так как он выполняется в под-оболочке. Чтобы убить сценарий, вы должны явно уничтожить его (по крайней мере, это единственный способ, который я знаю).
Вот небольшой скрипт о том, как это сделать:
Это лучший ответ, но все еще неполный, и я действительно не знаю, как избавиться от части бума .
источник