Освоение отладки Bash-скриптов: основные методы для разработчиков
Отладка Bash-скриптов с помощью проверки синтаксиса, xtrace, строгого режима, ловушек, ShellCheck и целенаправленного логирования.
Освоение отладки Bash-скриптов: основные методы для разработчиков
Отладка Bash-скриптов начинается с одного вопроса: где скрипт сделал что-то не так, как вы ожидали? Хорошая отладка дает вам видимость синтаксических ошибок, развернутых переменных, порядка команд и кодов завершения, не превращая скрипт в шум.
Это руководство описывает практические методы отладки Bash, которые вы можете использовать в реальном скрипте автоматизации до того, как он попадет в cron, CI или продакшн.
Начните с проверки синтаксиса
Прежде чем отслеживать поведение во время выполнения, убедитесь, что Bash может разобрать файл:
bash -n ./deploy.sh
bash -n читает скрипт и сообщает о синтаксических ошибках без выполнения команд. Он ловит пропущенные fi, done, then, кавычки и скобки. Он не поймает логические ошибки, отсутствующие файлы или команды, которые завершаются ошибкой во время выполнения.
Например, эта опечатка будет поймана до того, как что-либо выполнится:
if [ -f "$CONFIG" ]; then
echo "Config found"
# пропущен fi
Запускайте проверку синтаксиса после больших правок и перед добавлением дополнительного отладочного вывода.
Отслеживайте выполнение с помощью set -x
Самый полезный встроенный отладчик — это xtrace:
set -x
some_command "$VALUE"
set +x
С включенным отслеживанием Bash печатает каждую команду после раскрытия и перед выполнением. Это помогает увидеть, пуста ли переменная, раскрылся ли глоб, или команда получила другие аргументы, чем вы ожидали.
Для отслеживания всего скрипта запустите:
bash -x ./deploy.sh
Для более чистого отслеживания установите PS4, чтобы каждая строка включала номер строки исходного кода:
export PS4='+ ${BASH_SOURCE}:${LINENO}: '
bash -x ./deploy.sh
Если ваш скрипт обрабатывает секреты, не отслеживайте разделы, которые печатают токены, пароли или подписанные URL. Отключайте отслеживание перед этими командами:
set +x
login_with_secret "$API_TOKEN"
set -x
Добавляйте строгий режим с осторожностью
Эти опции ловят распространенные ошибки раньше:
set -euo pipefail
set -e завершает работу при многих необработанных сбоях команд. set -u рассматривает неопределенные переменные как ошибки. set -o pipefail заставляет конвейер завершаться ошибкой, если любая команда в конвейере завершается ошибкой, а не только последняя.
Они полезны, но не заменяют явную обработку. Такие команды, как grep, могут вернуть 1 для обычного результата "не найдено":
if grep -q "READY" status.txt; then
echo "ready"
else
echo "not ready"
fi
Это понятнее, чем скрывать результат с помощью grep -q "READY" status.txt || true.
Выводите правильные значения
Целенаправленное логирование лучше разбросанных строк echo. Выводите значения, которые влияют на ветку, которую вы отлаживаете:
printf 'DEBUG: user=%q env=%q target=%q\n' "$USER_NAME" "$ENVIRONMENT" "$TARGET_HOST" >&2
printf '%q' показывает значения с экранированием оболочки, что делает пробелы и специальные символы более заметными. Отправляйте отладочный вывод в stderr, чтобы нормальный вывод скрипта оставался пригодным для использования в конвейерах.
Когда команда завершается ошибкой, сразу же фиксируйте ее статус:
run_migration
status=$?
if [ "$status" -ne 0 ]; then
echo "Migration failed with exit code $status" >&2
exit "$status"
fi
Не выполняйте другую команду перед сохранением $?, потому что даже echo заменяет его.
Отладка циклов и условных операторов
Ошибки в циклах часто возникают из-за разделения слов или неожиданного ввода. Заключайте переменные в кавычки и читайте строки безопасно:
while IFS= read -r line; do
printf 'line=%q\n' "$line" >&2
done < input.txt
Для условных операторов выводите точные значения, которые сравниваются:
printf 'expected=%q actual=%q\n' "$EXPECTED" "$ACTUAL" >&2
if [[ "$ACTUAL" == "$EXPECTED" ]]; then
echo "match"
fi
Если вам нужно приостановить выполнение внутри скрипта во время локальной отладки, используйте read:
read -r -p "Press Enter to continue..."
Удаляйте паузы перед фиксацией скрипта, особенно если он может выполняться без присмотра.
Используйте ShellCheck для статического анализа
ShellCheck ловит многие проблемы, которые Bash будет с радостью выполнять, пока они не сломаются в крайнем случае:
shellcheck ./deploy.sh
Он отмечает незаключенные в кавычки переменные, недостижимый код, подозрительные проверки, неиспользуемые переменные и проблемы переносимости. Относитесь к предупреждениям как к приглашению проверить код, а не как к автоматическому доказательству того, что скрипт неправильный. Иногда вы можете намеренно отключить предупреждение, но добавьте краткий комментарий с объяснением почему.
Используйте trap, чтобы увидеть строку с ошибкой
Для более длинных скриптов ловушка ошибок может сообщить вам, где произошел сбой:
set -Eeo pipefail
trap 'echo "Error on line $LINENO: $BASH_COMMAND" >&2' ERR
set -E помогает ловушке ERR распространяться на функции и подоболочки в Bash. Это полезно в журналах CI, где у вас может не быть интерактивной оболочки.
Вывод
Начните с bash -n, используйте bash -x или целенаправленный set -x для отслеживания во время выполнения и добавьте целенаправленное логирование в stderr вокруг ветки, которая ведет себя неправильно. Для важных скриптов запустите ShellCheck и добавьте ловушку ERR, чтобы ошибки указывали на команду и строку, требующие внимания.