Ответ
Обработка ошибок в 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