Я пишу script в Bash для проверки кода. Однако, кажется, глупо запускать тесты, если компиляция кода не выполняется в первую очередь, и в этом случае я просто прекращу тесты.
Есть ли способ сделать это, не обертывая весь script внутри цикла while и используя разрывы? Что-то вроде dun dun dun goto?
Попробуйте следующее утверждение:
exit 1
Замените 1
соответствующими кодами ошибок. См. Также Коды выхода со специальными значениями.
Используйте set -e
#!/bin/bash
set -e
/bin/command-that-fails
/bin/command-that-fails2
script завершится после первой строки, которая не сработает (возвращает ненулевой код выхода). В этом случае command-that-fail2 не будет работать.
Если вы хотите проверить статус возврата каждой отдельной команды, ваш script будет выглядеть так:
#!/bin/bash
# I'm assuming you're using make
cd /project-dir
make
if [[ $? -ne 0 ]] ; then
exit 1
fi
cd /project-dir2
make
if [[ $? -ne 0 ]] ; then
exit 1
fi
С set -e он будет выглядеть так:
#!/bin/bash
set -e
cd /project-dir
make
cd /project-dir2
make
Любая сбой команды приведет к сбою всего script и возвращает статус выхода, который вы можете проверить с помощью $?. Если ваш script очень длинный или вы создаете много вещей, он будет довольно уродливым, если вы все равно добавите проверки статуса возврата.
set -e
Вы все еще можете сделать некоторые команды выхода с ошибками без остановки сценария: command 2>&1 || echo $?
,
(cd tmp && make)
Плохой парень SysOps однажды научил меня технике с тремя пальцами:
yell() { echo "$0: $*" >&2; }
die() { yell "$*"; exit 111; }
try() { "$@" || die "cannot $*"; }
Эти функции: * NIX OS и оболочка - надежные. Поместите их в начало вашего script (bash или иначе), try()
вашего оператора и кода.
(на основе летящих овец).
yell
: напечатайте имя script и все аргументы stderr
:
$0
- это путь к script;$*
- все аргументы.>&2
означает >
перенаправление stdout to и pipe 2
. pipe 1
будет stdout
.die
делает то же самое, что и yell
, но выходит с не-0 статусом выхода, что означает "сбой".try
использует ||
(boolean OR
), который оценивает только правую сторону, если левая не сработала.
$@
- все аргументы снова, но разные.Надеюсь, что все объясняет.
$0
- это путь к сценарию. $*
все аргументы. >&2
означает « >
перенаправить стандартный вывод на &
pipe 2
». труба 1 была бы самой stdout. поэтому yell префиксирует все аргументы с именем скрипта и печатает в stderr. die делает то же самое, что и yell , но выходит со статусом выхода не равным 0, что означает «сбой». попробуйте использовать логическое или ||
, который оценивает только правую сторону, если левая не провалилась. $@
снова все аргументы, но разные . надеюсь, что это все объясняет
Если вы вызовете script с помощью source
, вы можете использовать return <x>
, где <x>
будет статусом выхода script (используйте ненулевое значение для ошибки или false). Это также будет работать, как ожидалось, когда вы source
script. Если вы вызываете исполняемый файл script (т.е. Напрямую с его именем файла), оператор return приведет к жалобе (сообщение об ошибке "return: может только" возвращать "из функции или источника script" ).
Если вместо exit <x>
используется exit <x>
, когда script вызывается с помощью source
, это приведет к выходу из оболочки, которая запустила script, но исполняемый script будет работать нормально.
Чтобы обрабатывать любой случай в том же script, вы можете использовать
return <x> 2> /dev/null || exit <x>
Это будет обрабатывать любой вызов, который может быть подходящим.
Примечание: <x>
должно быть просто числом.
Я часто включаю функцию, называемую run() для обработки ошибок. Каждый вызов, который я хочу сделать, передается этой функции, поэтому весь script завершается при ударе. Преимущество этого решения в решении -e заключается в том, что script не выходит молча, когда линия выходит из строя, и может рассказать вам, в чем проблема. В следующем примере 3-я строка не выполняется, так как script выходит при вызове false.
function run() {
cmd_output=$(eval $1)
return_value=$?
if [ $return_value != 0 ]; then
echo "Command $1 failed"
exit -1
else
echo "output: $cmd_output"
echo "Command succeeded."
fi
return $return_value
}
run "date"
run "false"
run "date"
Вместо конструкции if
вы можете использовать оценку короткого замыкания:
#!/usr/bin/env bash
echo $[1+1]
echo $[2/0] # division by 0 but execution of script proceeds
echo $[3+1]
(echo $[4/0]) || exit $? # script halted with code 1 returned from `echo`
echo $[5+1]
Обратите внимание на пару круглых скобок, которая необходима из-за приоритета оператора чередования. $?
- это специальный набор переменных для выхода из кода последней вызванной команды.
command -that --fails || exit $?
это работает без скобок, что насчет echo $[4/0]
что заставляет нас нуждаться в них?
echo $[4/0] || exit $?
Простого echo $[4/0] || exit $?
) Bash никогда не выполнит echo
, не говоря уже о том, чтобы подчиняться ||
,
1
последовательно. Если сценарий предназначен для запуска другим сценарием, вы можете определить свой собственный набор кодов состояния с определенным значением. Например,1
== тесты не пройдены,2
== ошибка компиляции. Если сценарий является частью чего-то другого, вам может потребоваться настроить коды в соответствии с используемыми там практиками. Например, когда часть набора тестов запускается automake, код77
используется для обозначения пропущенного теста.