Был ли у вас опыт отладки скриптов (Bash, Python и др.)?

«Был ли у вас опыт отладки скриптов (Bash, Python и др.)?» — вопрос из категории Скриптинг и автоматизация, который задают на 23% собеседований Devops Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Да, отладка скриптов — это ежедневная часть моей работы в DevOps. Использую разные подходы в зависимости от языка и сложности проблемы.

Для Bash-скриптов:

  • set -x / set -v: Самый быстрый способ увидеть, какие команды выполняются и с какими аргументами.
  • set -e / set -o pipefail: Заставляю скрипт немедленно завершаться при ошибке любой команды или в пайплайне, чтобы проблема не была проигнорирована.
  • Временное логирование: Добавляю echo "[DEBUG] Переменная VAR = $VAR" в ключевых местах.
  • Анализ кодов возврата: Проверяю $? после выполнения сомнительных команд.

Пример отладочного Bash-скрипта:

#!/bin/bash
# Строгий режим для отладки
set -xeo pipefail

CONFIG_FILE="${1:-/etc/app/config.yaml}"
echo "DEBUG: Using config file: $CONFIG_FILE"

if [[ ! -f "$CONFIG_FILE" ]]; then
    echo "ERROR: Config file not found!" >&2
    exit 1
fi

# Использование strace для анализа системных вызовов, если скрипт "зависает"
# strace -f -o debug.log ./some_subprocess.sh

Для Python-скриптов:

  • Модуль logging: Настраиваю детальное логирование с разными уровнями (DEBUG, INFO, ERROR).
  • Интеграция с системным журналом: Через logging.handlers.SysLogHandler.
  • Отладчик pdb: Для интерактивного пошагового анализа сложных сценариев.
  • Валидация входных данных: Использую argparse с type-checking и try/except блоки для обработки ошибок.

Пример структуры Python-скрипта с отладкой:

import logging
import sys

logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[logging.StreamHandler(sys.stderr)]
)
logger = logging.getLogger(__name__)

def main(config_path):
    logger.info(f"Starting script with config: {config_path}")
    try:
        # Основная логика
        with open(config_path, 'r') as f:
            data = f.read()
        logger.debug(f"Read {len(data)} bytes from config.")
        # ...
    except FileNotFoundError as e:
        logger.error(f"Critical error: Config file not found. {e}")
        sys.exit(1)
    except Exception as e:
        logger.exception(f"Unexpected error occurred: {e}")  # Выводит traceback
        sys.exit(2)

if __name__ == "__main__":
    # Для активации pdb можно добавить: import pdb; pdb.set_trace()
    main(sys.argv[1] if len(sys.argv) > 1 else "default.conf")

В крайних случаях для анализа проблем с процессами или файлами использую системные утилиты strace/dtrace и lsof.