Войти в сентябрь было непросто, но большую часть задач удалось успешно закрыть. В очередной раз убеждаюсь, что не стоит давать разработчикам 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 не трогая ничего остального.
Тема вроде очень простая, но всегда вызывает вопросы и недоумение — В смысле код ошибки? Какой еще ошибки? А что так можно было?
Давай краба, завтра увидимся, хорошо тебе догулять выходные!







