Bash-скрипты, которые не падают: 5 привычек админа

Linux · Скрипты3 октября 20266 мин чтения

Почти у каждого админа есть история про скрипт, который «в проде» удалил не тот каталог или молча пропустил ошибку. Большинство таких историй предотвращается пятью привычками, которые занимают две минуты на скрипт.

1. set -euo pipefail — страховка по умолчанию

Первая строка после shebang:

#!/usr/bin/env bash
set -euo pipefail

Без pipefail конструкция mysqldump db | gzip > dump.gz радостно создаст пустой архив даже при упавшем dump — классика жанра.

2. Кавычки вокруг переменных. Всегда

cp "$source" "$destination"
for f in "$dir"/*; do ...; done

Без кавычек bash расколет значение по пробелам — и файл my report.pdf станет двумя аргументами. Единственное осознанное исключение — когда word splitting нужен намеренно, и тогда это стоит прокомментировать.

3. trap для уборки за собой

Скрипт, создающий временные файлы, обязан убрать их даже при падении посередине:

tmpdir=$(mktemp -d)
trap 'rm -rf "$tmpdir"' EXIT

trap ... EXIT срабатывает при любом завершении: успех, ошибка, Ctrl+C. Особенно ценно в скриптах, которые монтируют диски, блокируют ресурсы или оставляют lock-файлы.

4. [[ ]] вместо [ ]

if [[ -f "$config" && "$mode" == "prod" ]]; then
  echo "careful!"
fi

Двойные скобки — встроенная конструкция bash, а не внешняя команда: внутри не работает word splitting (кавычки не критичны), доступны &&, || и сравнение строк по шаблону == *.log. Меньше синтаксических граблей на ровном месте.

5. "$@" вместо $* в функциях

Передавая аргументы дальше, пишите "$@" в кавычках:

log_and_run() {
  echo "[$(date -Is)] $*" >> /var/log/runner.log
  "$@"
}

"$@" сохраняет каждый аргумент отдельным словом — аргумент с пробелами доедет до цели целым. $* склеит всё в одну строку. Для вывода в лог склейка уместна, для исполнения — нет, и разница видна на примере выше.

Бонус: shellcheck

apt install shellcheck
shellcheck backup.sh

Shellcheck ловит всё перечисленное автоматически и ещё полтысячи типовых ошибок. Есть расширения под любой редактор. Делать его запуск частью привычки «написал — проверил» — самый дешёвый ревьюер в команде.

Хороший bash-скрипт — это не тот, где «умно» решена задача, а тот, который при ошибке громко упал рядом с местом проблемы. Тихий скрипт с неверным результатом страшнее любого падения.

Пять привычек не делают из bash Python и не отменяют здравого смысла — но скрипт, написанный с ними, можно спокойно оставить в cron и уйти в отпуск.