Ответ
Обработка ошибок в Bash строится на кодах возврата (exit codes), функциях и команде trap. Я следую нескольким практикам для создания надежных скриптов.
1. Определение собственных кодов ошибок: Коды 1-127 доступны для пользовательских ошибок. Я документирую их в начале скрипта.
#!/bin/bash
# Коды ошибок:
# 1 - Общая ошибка
# 2 - Неверные аргументы
# 3 - Файл не найден
# 4 - Сетевая ошибка
# 5 - Ошибка проверки зависимостей
2. Функции с явным возвратом кода: Каждая функция возвращает 0 при успехе или свой код ошибки.
validate_port() {
local port=$1
# Проверка, что это число
if ! [[ "$port" =~ ^[0-9]+$ ]]; then
echo "Ошибка: порт должен быть числом" >&2
return 2
fi
# Проверка диапазона
if [ "$port" -lt 1 ] || [ "$port" -gt 65535 ]; then
echo "Ошибка: порт $port вне диапазона 1-65535" >&2
return 3
fi
return 0
}
3. Обработка ошибок в основном потоке:
Использую if или case для реакции на разные коды.
validate_port "$1"
exit_code=$?
case $exit_code in
0) echo "Порт $1 валиден.";;
2) echo "Ошибка валидации числа." >&2; exit 2;;
3) echo "Ошибка диапазона порта." >&2; exit 3;;
*) echo "Неизвестная ошибка." >&2; exit 1;;
esac
4. Глобальная обработка через trap:
Для перехвата EXIT, ERR и сигналов (TERM, INT).
# Выход при любой ошибке (неудачная команда)
set -e
# Выход при использовании неинициализированных переменных
set -u
cleanup() {
local exit_code=$?
echo "Скрипт завершился с кодом $exit_code"
# Удаление временных файлов, остановка процессов и т.д.
rm -f "${TMP_FILE:-}"
}
# Вызов cleanup при любом выходе из скрипта
trap cleanup EXIT
# Перехват сигналов для graceful shutdown
trap 'echo "Получен сигнал завершения"; exit 143;' TERM INT
5. Логирование: Все сообщения об ошибках направляю в stderr (>&2), а стандартный вывод оставляю для полезных данных. Для сложных скриптов добавляю логирование в файл с указанием времени и уровня (ERROR, WARN).
log_error() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] ERROR: $*" >&2
}
# Использование
log_error "Не удалось подключиться к хосту $DB_HOST"
exit 4 Ответ 18+ 🔞
А, ну ты глянь, обработка ошибок в баше! Тема, конечно, ебать мои старые костыли, но без неё — никуда. Сейчас разжую, как я это обычно делаю, чтобы скрипты не разваливались при первом же чихе.
1. Свои коды ошибок — это святое. Ну то есть, стандартные коды — это хорошо, но свои — лучше. Я их всегда в начале скрипта расписываю, чтобы потом самому не охуеть и другим понятно было.
#!/bin/bash
# Коды ошибок:
# 1 - Общая ошибка (ну, по дефолту)
# 2 - Аргументы кривые пришли
# 3 - Файл потерялся, блядь
# 4 - Сеть легла
# 5 - Зависимости не нашлись
2. Функции, которые не стесняются сказать, что нихуя не вышло. Каждая функция должна чётко отчитаться: 0 — всё заебись, не 0 — пошло что-то не так.
validate_port() {
local port=$1
# Проверяем, что это вообще цифры, а не хуйня какая-то
if ! [[ "$port" =~ ^[0-9]+$ ]]; then
echo "Ошибка: порт должен быть числом, а не '$port'" >&2
return 2 # Код для "неверные аргументы"
fi
# А теперь смотрим, чтоб в нормальном диапазоне был
if [ "$port" -lt 1 ] || [ "$port" -gt 65535 ]; then
echo "Ошибка: порт $port — это ёперный театр! Должен быть от 1 до 65535" >&2
return 3
fi
return 0 # Всё ок
}
3. В основном коде на эти коды надо реагировать.
Нельзя просто так взять и проигнорировать. Тут либо if, либо case — кому как удобнее.
validate_port "$1"
exit_code=$?
case $exit_code in
0) echo "Порт $1 — огонь, можно использовать.";;
2) echo "Ну ты чё, цифры введи нормальные." >&2; exit 2;;
3) echo "С портом ты явно переборщил, дружок." >&2; exit 3;;
*) echo "Хуй знает, что случилось, но что-то пошло не так." >&2; exit 1;;
esac
4. Глобальные ловушки — наше всё.
Вот это, блядь, мощнейшая штука — trap. Ставишь ловушку на выход, на ошибки, на сигналы — и скрипт убирает за собой, даже когда его убивают.
# Выходим сразу, если какая-то команда свалилась
set -e
# И если переменная не задана — тоже ата-та
set -u
cleanup() {
local exit_code=$?
echo "Всё, приехали. Код выхода: $exit_code"
# Тут подчищаем весь свой бардак: временные файлы, процессы...
rm -f "${TMP_FILE:-}"
}
# Эта функция вызовется ВСЕГДА, когда скрипт будет завершаться
trap cleanup EXIT
# А это чтобы на Ctrl+C или `kill` скрипт не сдох мгновенно, а вышел красиво
trap 'echo "Меня пытаются убить! Ладно, выхожу..."; exit 143;' TERM INT
5. Логирование — чтобы потом не было мучительно больно.
Все ошибки — строго в stderr (>&2), чтобы не пачкать нормальный вывод. А для серьёзных проектов заводишь лог-файл с датами и уровнями.
log_error() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] ERROR: $*" >&2
}
# Используем
if ! ping -c 1 "$DB_HOST" &> /dev/null; then
log_error "Хост $DB_HOST лежит, как тёща после застолья. Не дозвониться."
exit 4
fi
Вот так, вкратце. Главное — не надеяться на авось, а предвидеть, где всё может пойти по пизде, и подготовиться. Тогда и скрипт будет как швейцарские часы, а не как мартышлюшка с гранатой.