В сценарии Bash, как я могу выйти из всего сценария, если возникает определенное условие?


Я пишу сценарий в Bash, чтобы проверить некоторый код. Однако кажется глупым запускать тесты, Если компиляция кода не выполняется в первую очередь, и в этом случае я просто прерву тесты.

есть ли способ сделать это без обертывания всего сценария внутри цикла while и использования перерывов? Что-то вроде Дун Дун Дун Гото?

6 483

6 ответов:

попробуйте это заявление:

exit 1

заменить 1 с соответствующими кодами ошибок. Смотрите также Коды Завершения, Имеющие Предопределенный Смысл.

использовать set-e

#!/bin/bash

set -e

/bin/command-that-fails
/bin/command-that-fails2

скрипт завершится после первой строки, которая завершится неудачно (возвращает ненулевой код выхода). В этом случае command-that-fails2 не будет работать.

если бы вы проверяли состояние возврата каждой отдельной команды, ваш скрипт выглядел бы так:

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

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

один мерзкий Сисоп однажды научил меня технике трехпалого Когтя:

yell() { echo ": $*" >&2; }
die() { yell "$*"; exit 111; }
try() { "$@" || die "cannot $*"; }

эти функции * ОС Никс и вкус раковины-крепкий. Поставил их в начале вашего скрипта (bash или иначе), try() ваш оператор и код ВКЛ.

объяснение

(исходя из летающих овец комментарий).

  • yell: выведите имя скрипта и все аргументы в stderr:
    • - это путь к скрипту ;
    • $* все аргументы.
    • >&2 означает > перенаправить stdout в & pipe 2. труба 1 будет stdout сам по себе.
  • die делает то же самое, что и yell, но выходит с не-0 статус выхода, что означает "потерпеть неудачу".
  • try использует || (булево OR), который оценивает только правую сторону, если левая не подвел.
    • $@ это все аргументы снова, но разные.

надеюсь, что это все объясняет.

если вы вызовете скрипт с source, вы можете использовать return <x> здесь <x> будет состояние выхода скрипта (используйте ненулевое значение для error или false). Это также будет работать, как ожидалось, когда вы source сценарий. Если вы вызываете исполняемый сценарий (т. е. непосредственно с его именем файла), оператор return приведет к жалобе (сообщение об ошибке "return: может только"return" из функции или исходного сценария").

если exit <x> используется вместо этого, когда вызывается скрипт с source, это приведет к выходу из оболочки, которая запустила скрипт, но исполняемый скрипт будет работать непосредственно нормально.

для обработки любого случая в том же скрипте, вы можете использовать

return <x> 2> /dev/null || exit <x>

это будет обрабатывать любой вызов может быть подходящим.

Примечание: <x> - это должно быть просто число.

Я часто включаю функцию run () для обработки ошибок. Каждый вызов, который я хочу сделать, передается этой функции, поэтому весь скрипт завершается при сбое. Преимущество этого по сравнению с решением set-e заключается в том, что скрипт не выходит беззвучно при сбое строки и может рассказать вам, в чем проблема. В следующем примере 3-я строка не выполняется, потому что сценарий завершается при вызове false.

function run() {
  cmd_output=$(eval )
  return_value=$?
  if [ $return_value != 0 ]; then
    echo "Command  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]

обратите внимание на пару скобок, которая необходима из-за приоритета оператора чередования. $? - это переменная недавно выход из кода команды.