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

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

Есть ли способ сделать это, не обертывая весь script внутри цикла while и используя разрывы? Что-то вроде dun dun dun goto?

Ответ 2

Используйте 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 очень длинный или вы создаете много вещей, он будет довольно уродливым, если вы все равно добавите проверки статуса возврата.

Ответ 3

Плохой парень из SysOps однажды научил меня технике Трехпалого Когтя:

yell() { echo "$0: $*" >&2; }
die() { yell "$*"; exit 111; }
try() { "[email protected]" || die "cannot $*"; }

Эти функции * ОС NIX и оболочка устойчивы. Поместите их в начало вашего скрипта (bash или иным образом), try() ваше утверждение и код.

объяснение

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

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

Ответ 4

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

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

Чтобы обработать любой случай в одном и том же сценарии, вы можете использовать

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

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

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

Ответ 5

Я часто включаю функцию, называемую 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"

Ответ 6

Вместо конструкции 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]

Обратите внимание на пару круглых скобок, которые необходимы из-за приоритета оператора чередования. $? специальная переменная, установленная для выхода из кода последней вызванной команды.

Ответ 7

У меня тот же вопрос, но я не могу его задать, потому что это будет дубликат.

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

Вот небольшой скрипт о том, как это сделать:

#!/bin/bash

boom() {
    while true; do sleep 1.2; echo boom; done
}

f() {
    echo Hello
    N=0
    while
        ((N++ <10))
    do
        sleep 1
        echo $N
        #        ((N > 5)) && exit 4 # does not work
        ((N > 5)) && { kill -9 $$; exit 5; } # works 
    done
}

boom &
f &

while true; do sleep 0.5; echo beep; done

Это лучший ответ, но все еще неполный, и я действительно не знаю, как избавиться от части бума.