Напишите bash-скрипт, который находит в access-логе nginx топ-10 IP-адресов по числу запросов с ошибкой 5xx. Какие приёмы делают скрипт надёжным?
Короткий ответ
- Конвейер awk → sort → uniq -c → sort -rn → head
- set -euo pipefail для остановки на ошибках
- Проверка аргументов и существования файла
- awk фильтрует по коду ответа в нужном поле
- Кавычки вокруг переменных против пробелов в путях
- Для сжатых логов — zcat или zgrep
Задача решается классическим текстовым конвейером, а надёжность дают strict mode и проверки входных данных.
Как сказать вслух
пример ответаЭто классическая задача на текстовый конвейер: awk фильтрует строки с пятисотыми кодами и достаёт IP, дальше sort и uniq с подсчётом, сортировка по убыванию и head на десять строк. Чтобы скрипт был надёжным, я включаю строгий режим с set -euo pipefail, проверяю, что файл передан и существует, и беру переменные в кавычки. Такие однострочники — повседневный инструмент при разборе инцидентов прямо на сервере.
Подробный ответ
Основной ответ
В стандартном combined-формате nginx IP — первое поле, код ответа — девятое, поэтому основа решения: awk достаёт поля и фильтрует коды 500–599, затем sort | uniq -c | sort -rn | head -10. Надёжность: set -euo pipefail прерывает скрипт при ошибке любой команды, обращении к несуществующей переменной и падении внутри конвейера; проверка числа аргументов и читаемости файла с понятным сообщением в stderr и ненулевым кодом выхода; кавычки вокруг подстановок. Нюансы: формат лога может отличаться — поле кода лучше вынести в переменную; ротация и сжатие решаются zcat; при огромных файлах awk с ассоциативным массивом считает за один проход без промежуточного sort.
Ключевые моменты
- Строгий режим. set -euo pipefail — стандарт для продакшен-скриптов; без него ошибки молча проглатываются.
- Знание формата лога. Нужно понимать, в каком поле код и IP, а не слепо копировать числа полей.
- Конвейерное мышление. Интервьюер проверяет владение awk, sort, uniq — базовым набором для работы с текстом в Linux.
- Коды выхода. Ошибки — в stderr, выход с ненулевым кодом, чтобы скрипт корректно встраивался в автоматизацию.
Практический контекст
Такое задание дают на live-кодинге почти в каждом собеседовании DevOps/SRE: оно быстро показывает, работал ли человек с логами руками. В реальности этот паттерн используется при атаках и всплесках ошибок: найти источник аномального трафика до того, как построены дашборды. Ценится умение рассуждать вслух и адаптировать решение под уточнения — другой формат лога, сжатые файлы, миллионы строк.
Пример кода
#!/usr/bin/env bash
set -euo pipefail
log_file="${1:?Usage: $0 /path/to/access.log}"
if [[ ! -r "$log_file" ]]; then
echo "Error: cannot read $log_file" >&2
exit 1
fi
# combined-формат: $1 — IP, $9 — код ответа
awk '$9 ~ /^5[0-9][0-9]$/ {print $1}' "$log_file" \
| sort \
| uniq -c \
| sort -rn \
| head -10Частые ошибки
- Забывают sort перед uniq -c, получая неверные подсчёты
- Не проверяют аргументы и существование файла
- Используют цепочку из cat и лишних grep там, где достаточно одного awk