Перейти к содержанию

Отладка Bash-сценариев и безопасное выполнение

Bash в НАЙС.ОС CLOUD собирается из собственного пакета и формирует общесистемные профили. При этом правила исполнения shell-скриптов остаются особенностями Bash, которые важно понимать прежде, чем автоматизировать сеть, firewall или RPM-обновления.

1. Проверка синтаксиса без выполнения

bash --version | head -2
bash -n /path/to/script.sh

bash -n проверяет синтаксис, но не доказывает, что скрипт корректен логически: он не проверяет существование всех файлов, SSH-доступ, значения переменных или результат команд.

2. Отладка с трассировкой

bash -x /path/to/script.sh

Трассировка может раскрыть секреты

-x печатает команды после подстановки переменных. Пароли, токены и ключи могут попасть в журнал или терминальную историю. Не применяйте bash -x к скриптам с секретами без их маскирования и изолированной тестовой среды.

3. Ошибки set -euo pipefail

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

-e завершает выполнение при части ошибок команд, но поведение зависит от контекста (if, условные списки, подстановки); -u запрещает обращение к неустановленной переменной; pipefail меняет статус конвейера; -E наследует trap ERR в некоторых контекстах. Это мощные инструменты, но не гарантия транзакционности.

Проверьте поведение на изолированном тестовом файле:

set -o pipefail
false | true
printf 'exit=%s\n' "$?"

Без pipefail статус такой конструкции обычно берётся от последней команды. С pipefail конвейер считается ошибочным, если какая-то команда не завершилась успешно.

4. Безопасный шаблон скрипта

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

usage() {
  printf 'Использование: %s ПУТЬ_К_ФАЙЛУ\n' "$0" >&2
  exit 2
}

[[ $# -eq 1 ]] || usage
file=$1
[[ -f "$file" ]] || { printf 'Не найден файл: %s\n' "$file" >&2; exit 1; }

printf 'Размер файла в байтах: '
wc -c < "$file"

Скрипт только читает указанный файл, не меняет сеть и конфигурацию. Кавычки вокруг "$file" сохраняют пробелы и не дают shell выполнить непредусмотренное разбиение аргументов.

5. trap и очистка временных файлов

tmp=$(mktemp)
trap 'rm -f -- "$tmp"' EXIT
printf 'temporary\n' > "$tmp"

При завершении процесса trap обычно удалит временный файл; при SIGKILL, аварии питания или потере файловой системы обработчик не выполняется. Для операций над несколькими системными файлами этого недостаточно — нужен бэкап и план отката.

6. Важные ошибки

  • Не используйте eval для пользовательского ввода.
  • Не подставляйте в rm -rf непроверенный путь.
  • Для перебора файлов используйте null-разделители при необходимости, а не for f in $(ls).
  • Не рассчитывайте, что cron/systemd загрузят ваш интерактивный ~/.bashrc.
  • Для scripts в systemd задавайте абсолютные пути и явные переменные окружения.

7. Автоматизация для НАЙС.ОС

Перед включением скрипта в timer/systemd-run тестируйте его на копии данных, отслеживайте journalctl, определяйте повторное выполнение и блокировки (flock при необходимости). Обновление firewall и сети должно иметь проверенный откат; одна лишь set -e не спасёт от потери SSH.

Источники: Core/bash/SPECS/bash.spec; Bash Reference Manual.