Выход из скрипта Bash: exit 0 и exit 1 с пояснениями

Зачем нужно выходить из скрипта Bash?

Допустим, вы пишете сценарий… есть одна вещь, которая почти наверняка…

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

Итак, что можно с этим сделать?

Как выйти из скрипта Bash в случае возникновения ошибок?

Bash предоставляет команду выхода из скрипта в случае возникновения ошибок, команду выхода. Аргумент N (статус выхода) может быть передан команде выхода, чтобы указать, был ли скрипт выполнен успешно (N = 0) или неудачно (N!= 0). Если N опущено, команда выхода принимает статус выхода последней выполненной команды.

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

Давайте начнем.

Завершить Bash-скрипт с ошибкой

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

Ответ на этот вопрос: не забывайте об обработке ошибок.

Вместо того чтобы «надеяться», что с вашей программой все будет в порядке, вы можете предсказать возможные сбои и решить, как ваша программа будет на них реагировать.

Как вы будете справляться с ошибками, если они возникнут? Что увидит пользователь?

Мы рассмотрим, как работает обработка ошибок в скриптах Bash (или скриптах Shell в целом).

Эти концепции применимы ко всем языкам программирования, даже если способы обработки ошибок в них реализованы по-разному.

Для обработки ошибок в Bash мы будем использовать команду exit, синтаксис которой следующий:

exit N

Где N — код выхода Bash (или статус выхода), используемый для выхода из скрипта во время его выполнения.

Различные значения N указывают на успешное или неудачное завершение скрипта.

Но почему разные коды завершения зависят от успеха или неудачи сценария?

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

Завершить Bash-скрипт с ошибкой

Давайте посмотрим, что означает выход 1.

Что такое Exit 0 и Exit 1 в скрипте Bash?

Как выйти из скрипта Bash в случае ошибки?

Стандартное соглашение следующее:

Код выхода BashЗначение
Ноль (0)Успех
Ненулевое (1, 2, 3 и т. д.)Отказ

Как видно из таблицы выше, сбои могут быть представлены любыми ненулевыми кодами выхода.

Например:

  • 1 может использоваться, если скрипту переданы неверные аргументы
  • 2 если скрипт не может найти нужный ему файл
  • 3 если нужный файл имеет неправильный формат
  • И так далее…

Вы можете проявить творческий подход и использовать ненулевые коды выхода Bash, чтобы четко определить причину сбоя вашего скрипта.

Итак, возвращаемся к команде выхода.

Что произойдёт, когда он будет выполнен?

Команда выхода возвращает код выхода обратно в оболочку.

Вот пример…

Давайте напишем скрипт под названием exit_status.sh:

#!/bin/bash

echo "Exit command test"
exit 0 

Итак, здесь мы передаем код выхода 0 команде выхода.

Как мы можем проверить, что это действительно тот код, который скрипт передал обратно в оболочку?

Мы используем переменную $?. Запомните это, это очень важно!

$? — переменная, содержащая код завершения последней выполненной команды.

И как мы можем определить его значение?

Используя команду echo, мы таким же образом выводим значение любой переменной:

(localhost)$./exit_status.sh 
Exit command test
(localhost)$ echo $?
0

Вуаля, вот код выхода 0.

А что произойдет, если мы уберем «выход 0» из скрипта?

#!/bin/bash

echo "Exit command test"

Запустите скрипт еще раз и проверьте значение $?:

(localhost)$./exit_status.sh 
Exit command test
(localhost)$ echo $?
0

Мы все равно получаем код выхода 0…

Итак, ничего не изменилось… почему?

Потому что каждая выполняемая нами команда, включая команду echo (единственная команда в нашем скрипте), возвращает код выхода.

В этом случае команда echo, выполненная как часть скрипта, возвращает код завершения 0, поскольку команда echo «Exit command test» выполнена успешно.

Подробнее о статусе команды Bash Exit

Я покажу вам пример того, как код выхода применяется к выполнению любых команд.

Это действительно важно для вашего знания Bash, и я хочу убедиться, что вам это понятно.

Вот пример с командой cat (это применимо ко всем командам)…

Я открываю оболочку на своем компьютере и в текущем каталоге у меня есть следующие файлы:

(localhost)$ ls -al
total 16
drwxr-xr-x   4 myuser  mygroup  128  4 Jul 12:38.
drwxr-xr-x  11 myuser  mygroup  352  4 Jul 12:38..
-rw-r--r--   1 myuser  mygroup   10  4 Jul 12:38 test_file1
-rw-r--r--   1 myuser  mygroup   10  4 Jul 12:38 test_file2

Если я использую команду cat для просмотра содержимого файла test_file1, то код выхода, сохраненный в переменной $? после выполнения команды cat, равен 0, поскольку выполнение команды cat прошло успешно:

(localhost)$ cat test_file1 
Test file
(localhost)$ echo $?
0

Если по ошибке я попытаюсь распечатать содержимое файла test_file3 (который не существует), значение переменной $? не будет равно 0.

В этом случае это 1, но он может иметь и другие значения, отличные от нуля. Это полезно для представления нескольких типов ошибок для данной команды:

(localhost)$ cat test_file3
cat: test_file3: No such file or directory
(localhost)$ echo $?
1

Все ясно?

Если у вас есть какие-либо вопросы, пожалуйста, дайте мне знать в комментариях ниже.

Пример провала сценария

Теперь давайте изменим команду echo в простом скрипте, который мы использовали ранее.

Мы хотим запустить его с неправильным синтаксисом и посмотреть, завершится ли он с ненулевым кодом выхода.

Удалите двойные кавычки в конце команды echo, как показано ниже:

#!/bin/bash

echo "Exit command test

Если мы выполним скрипт, то увидим сообщение «syntax error: unexpected end of file»:

(localhost)$./exit_status.sh 
./exit_status.sh: line 3: unexpected EOF while looking for matching `"'
./exit_status.sh: line 4: syntax error: unexpected end of file
(localhost)$ echo $?
2

А код выхода — 2. То есть, ненулевой код выхода, как мы и ожидали.

Как упоминалось ранее, помните о переменной $?, поскольку она имеет большое значение при обработке ошибок и делает ваши скрипты более надежными.

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

Bash If Else применен к переменной $?

Давайте посмотрим, как можно использовать оператор Bash if else вместе с переменной $?.

Следующий скрипт пытается создать подкаталог tmp/project в текущем каталоге.

В условии оператора if мы проверяем, отличается ли значение переменной $? от 0. Если это так, мы выводим сообщение об ошибке и завершаем работу скрипта с кодом выхода 1.

Ветвь else выводит сообщение об успешном выполнении и выполняется только в том случае, если значение $? равно 0.

#!/bin/bash
  
mkdir tmp/project

if [[ $? -ne 0 ]] ; then
    echo "Unable to create directory tmp/project"
    exit 1
else
    echo "Directory tmp/project created successfully"
fi

Давайте запустим скрипт:

(localhost)$./exit.sh 
mkdir: tmp: No such file or directory
Unable to create directory tmp/project
(localhost)$ echo $?
1

Команда mkdir завершается ошибкой, поскольку каталог tmp не существует, и, как и ожидалось, статус завершения скрипта равен 1.

Я хочу посмотреть, что произойдет, если я обновлю команду mkdir в скрипте, включив флаг -p, который создает каталог tmp, если он не существует:

mkdir -p tmp/project

Вот результат работы скрипта:

(localhost)$./exit.sh 
Directory tmp/project created successfully
(localhost)$ echo $?
0

На этот раз каталог создан успешно, а код выхода, возвращаемый скриптом, равен нулю, как и ожидалось (выполняется ветвь else оператора if else).

Заключение

Мы через многое прошли!

Теперь вы знаете:

  • Почему в скриптах Bash используются выходы 0 и 1.
  • Как можно использовать переменную $? для чтения кода выхода, возвращаемого командой (или скриптом)
  • Способ использования оператора Bash if else вместе с переменной $?.

А теперь ваша очередь…

Какие неудачи вы хотели бы учесть в своем сценарии?