Надёжность: set -euo pipefail, trap, отладка
Делаем скрипты предсказуемыми: останавливаемся на ошибках и убираем за собой.
set -euo pipefail — это набор строгих режимов Bash, которые заставляют скрипт падать на первой же ошибке вместо тихого продолжения.
Проблема: Bash слишком прощающий
По умолчанию Bash игнорирует ошибки: если команда упала, скрипт спокойно идёт дальше — и можно, например, удалить файлы в пустой переменной пути. Лечится строгим режимом в начале скрипта:
#!/usr/bin/env bash
set -euo pipefailРазберём по буквам: -e — выйти при ошибке любой команды; -u — ошибка при использовании необъявленной переменной; -o pipefail — конвейер падает, если упала любая его команда, а не только последняя.
| Флаг | Что делает |
-e | выход при первой ошибке |
-u | ошибка на необъявленной переменной |
-o pipefail | ловит сбой внутри конвейера |
Зачем -u спасает от катастроф
#!/usr/bin/env bash
set -u
rm -rf "$BUILDDIR/cache"Если BUILDDIR забыли задать, без -u путь стал бы /cache и могла начаться беда. С -u скрипт сразу упадёт с ошибкой «unbound variable» — и ничего не удалит.
trap: уборка при выходе
trap ловит сигналы и событие выхода, чтобы выполнить уборку — удалить временные файлы, снять блокировку.
#!/usr/bin/env bash
set -euo pipefail
tmpfile=$(mktemp)
cleanup() {
rm -f "$tmpfile"
echo "Временные файлы удалены"
}
trap cleanup EXIT
echo "данные" > "$tmpfile"
# ... работа со скриптом ...Команда trap cleanup EXIT гарантирует, что функция cleanup выполнится при ЛЮБОМ завершении скрипта — нормальном, по ошибке или по Ctrl+C. Временный файл точно удалится.
Отладка через set -x
Когда скрипт ведёт себя загадочно, включите трассировку: set -x печатает каждую команду перед выполнением с подставленными переменными.
set -x
name="мир"
echo "Привет, $name"
set +xВывод:
+ name=мир + echo 'Привет, мир' Привет, мир
Строки с + — это трассировка: видно реальные значения переменных. set +x выключает режим. Можно запустить весь скрипт с трассировкой: bash -x script.sh.
Как работает под капотом
Флаги set переключают внутренние режимы оболочки. -e заставляет Bash проверять код возврата каждой простой команды и завершаться при ненулевом (с рядом исключений — например, в условиях if). trap регистрирует обработчик на сигнал или псевдособытие EXIT; Bash вызывает его перед фактическим завершением. -x печатает каждую раскрытую команду в stderr с префиксом из переменной PS4 (по умолчанию +).
Частые ошибки
- -e и команды, которые «нормально» возвращают не 0. Например,
grepбез совпадений вернёт 1 и уронит скрипт. Оборачивайте:grep x file || true. - Забыть pipefail. Без него
ложная_команда | tee logсчитается успешной, потому чтоteeотработал. - trap без EXIT. Уборку вешайте на
EXIT, чтобы она срабатывала при любом выходе, а не только по конкретному сигналу.
Итог
set -euo pipefailв начале скрипта превращает тихие ошибки в явные падения.trap cleanup EXITгарантирует уборку при любом завершении скрипта.set -x(илиbash -x) трассирует выполнение — главный инструмент отладки.