Войти в сентябрь было непросто, но большую часть задач удалось успешно закрыть. В очередной раз убеждаюсь, что не стоит давать разработчикам root доступ к серверам. Эта оплошность стоила мне 3х дней безвылазного дебага на проде и кучи нервов. Ладно, всякое бывает. Сегодня поговорим про статусы выхода в bash.



Каждая программа в linux возвращает некий статус, был ли успех по завершению или возникла ошибка. Этими статусами можно гибко управлять в своих bash скриптах для отображения нужных ошибок.



К примеру мой вело-скрипт для бэкапов основан на команде tar и в какой-то момент оно начало возвращать ошибку. Бэкапы соответственно перестали делаться, но я про это ничего не знаю. Но добавив в скрипт обработку ошибок, я получил неплохой триггер, который в случае факапа накричит мне в телеграм. А я успешно это прочитаю и забью болт 📺 рабочие будни.



Статус выхода, это целое число от 0-255, где 0 это успешное завершение команды/программы. Все остальные коды, это ошибки.



Например, если программа не найдена ни в одном из путей $PATH либо ее вообще нет в системе, то оболочка вернет 127 код ошибки. Ну а если команда/программа найдена, но не является исполняемой, то мы получим код 126 (Permission denied).



Чтобы сделать программу/скрипт исполняемым, ставь специальный аттрибут: chmod +x <program/script>



Как отловить код выхода из программы/скрипта



Все очень просто, существует специальная зарезервированная переменная «$?», которая будет хранить в себе как раз тот самый код выхода. Теперь наглядно, запускаем:



# date

# echo $?

0



Видим что прилетел 0, окей, команда отработала успешно. Теперь запустим так:



# bashdays

# echo $?

127



Как видим вернулся код 127, как я писал выше, этот код означает, что не удалось найти программу с именем bashdays.



Понятно? Думаю вообще все прозрачно. Имея эту информацию, можно строить гибкую логику в скриптах и обрабатывать эксепшены.



Чтобы сохранить код в обычную переменную, делаем так:



#/bin/bash



date

code=$?

echo "exit code : ${code}"



Теперь в переменной code будет храниться код завершения. Даже если ты запустишь следом другие команды, в переменной code будет лежать предыдущий код выхода.



Рассмотрим ситуацию с логикой:



#!/bin/bash



date

code=$?



if test $code -eq 0

then

echo "success"

else

echo "failed"

fi



test - предназначена для проверки типа файла и сравнения чисел и строк. Возвращает код возврата 0 (истина) или 1 (ложь) в зависимости от вычисления выражения. Выражения могут быть как унарными, так и бинарными.



Если команда date вернет 0 (-eq - означает равно), скрипт завершится со статусом 0 = success, во всех других статусах мы получим failed.



Так же ты можешь самостоятельно возвращать нужные тебе коды в своих скриптах. Я использую этот способ в пайплайнах, когда gitlab считает что завершил сборку успехом, но на самом деле это не так. Подкидываешь ему exit 1 и пайплайн уже не зеленый, а красный.



Рассмотрим пример:



#!/bin/bash



date

time

exit 1

echo "hello"



После запуска, выполнятся две команды date и time, затем всё завершится с кодом 1 не передав управление команде echo.



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



Тема вроде очень простая, но всегда вызывает вопросы и недоумение — В смысле код ошибки? Какой еще 🤒 ошибки? А что так можно было?



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



Давай краба, завтра увидимся, хорошо тебе догулять выходные!



tags: #bash



💩 @bashdays