awk и sed: обрабатываем логи без открытия файлов

Друзья, давайте честно: сколько раз вы пытались открыть лог-файл размером в пару гигабайт в текстовом редакторе? И сколько раз редактор "не отвечал", "зависал", "кушал всю память" и просто "умирал"?

Я через это проходил. Notepad++ падал, Sublime Text думал минут по пять, а Vim просто говорил "ну ты чего, это же 500 мегабайт, я не камикадзе".

И только потом до меня дошло: лог-файлы не предназначены для открытия. Их предназначение — быть обработанными. А для этого есть два древних, но бессмертных инструмента: awk и sed.

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

Почему awk и sed, а не Python

Я люблю Python. Но когда нужно быстро посмотреть, что происходит в логе "на живую", писать скрипт — это как вызывать сантехника, чтобы лампочку поменять.

awk и sed — это швейцарские ножи консоли. Они: - Не загружают весь файл в память (читают построчно) - Работают мгновенно даже на гигабайтных файлах - Есть на любом Linux-сервере по умолчанию - Позволяют делать сложные преобразования одной строкой

Выучив базовые приёмы, вы сэкономите себе часы жизни.

Sed: король замен и удалений

sed (Stream EDitor) — это редактор потоков. Он читает файл построчно, применяет к строке команды и выводит результат.

Базовый синтаксис

bash sed 'команда' файл

Самые частые команды: - s/что/на что/ — замена (substitute) - /шаблон/d — удалить строки, подходящие под шаблон - p — печать (обычно с флагом -n)

Замена текста (kill -9 ошибкам)

Допустим, в логе много путей вида /home/user/project/logs/..., а нам нужно коротко.

bash sed 's/\/home\/user\/project\/logs\///g' app.log

Проблема: слеши экранировать муторно. Используем другой разделитель:

bash sed 's|/home/user/project/logs/||g' app.log

Уже лучше. А теперь реальный пример: в логах nginx IP-адреса вида 192.168.1.100, а нам нужно заменить последний октет на XXX для анонимизации:

bash sed -E 's/([0-9]+\.[0-9]+\.[0-9]+\.)[0-9]+/\1XXX/g' access.log

-E включает расширенные регулярки, чтобы не экранировать скобки и плюсы.

Удаление мусора

В логах часто бывают строки, которые только мешают. Например, бесконечные "heartbeat" сообщения.

bash sed '/heartbeat/d' app.log

Или удалить всё, кроме ошибок:

bash sed -n '/ERROR/p' app.log

Флаг -n говорит "не печатай ничего по умолчанию", а p в конце — "напечатай, если нашёл ERROR".

Удаление ANSI-цветов

Если вы когда-нибудь перенаправляли вывод цветного приложения в файл, то знаете эту боль: ^[[31mОшибка^[[0m. Удаляем:

bash sed -E 's/\x1b\[[0-9;]*m//g' colorful.log

Работа с диапазонами

Иногда нужно вырезать кусок лога между двумя маркерами. Например, с момента запуска до первой ошибки:

bash sed -n '/START/,/ERROR/p' app.log

Это напечатает все строки от первой встретившейся "START" до первой "ERROR" включительно.

Редактирование "на месте"

Флаг -i (in-place) меняет файл без создания нового. Осторожно!

bash sed -i.bak 's/старое/новое/g' app.log

Создаст резервную копию app.log.bak и изменит оригинал.

Awk: король полей и отчётов

Если sed — это про замену текста, то awk — это про работу со структурированными данными. Он воспринимает строку как набор полей и позволяет с ними работать.

Базовый синтаксис

bash awk '/шаблон/ {действие}' файл

По умолчанию поля разделяются пробелами или табами. К полям обращаются как $1, $2, $0 — вся строка.

Вырезаем колонки

Классика: лог nginx — вытащить только IP и URL.

bash awk '{print $1, $7}' access.log

$1 — IP, $7 — обычно URL (зависит от формата лога).

Фильтрация по значениям

Показать только запросы, которые вернули 500-ю ошибку:

bash awk '$9 == 500 {print $1, $7, $9}' access.log

$9 — код ответа.

Статистика одной строкой

Сколько запросов от каждого IP?

bash awk '{count[$1]++} END {for (ip in count) print ip, count[ip]}' access.log | sort -rn -k2

Разбираем: - {count[$1]++} — для каждого уникального $1 увеличиваем счётчик - END {for ...} — после обработки всего файла печатаем результат - sort -rn -k2 — сортируем по убыванию второго поля (числа запросов)

Работа с CSV и TSV

Если разделитель не пробел, задаём свой:

bash awk -F ',' '{print $1, $3}' data.csv

-F ',' — разделитель запятая.

Арифметика

Посчитать среднее время ответа (если в логе есть поле с временем):

bash awk '{sum += $10; count++} END {print "Average:", sum/count}' access.log

Условные операторы

Показать запросы, которые длились дольше 5 секунд:

bash awk '$10 > 5000 {print $1, $7, $10}' access.log

Регулярки

Найти все запросы к админке:

bash awk '$7 ~ /admin/ {print $1, $7}' access.log

Форматированный вывод

printf работает как в Си:

bash awk '{printf "IP: %-15s URL: %s\n", $1, $7}' access.log

Связка команд: конвейер смерти

Настоящая магия начинается, когда вы комбинируете sed, awk, grep, sort, uniq и head в конвейерах.

Пример 1: Топ-10 IP по количеству запросов

bash awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -10

  • awk вырезает IP
  • sort сортирует
  • uniq -c считает уникальные
  • sort -rn сортирует по убыванию чисел
  • head -10 берёт первые 10

Пример 2: Запросы с 404-й ошибкой, сгруппированные по URL

bash awk '$9 == 404 {print $7}' access.log | sort | uniq -c | sort -rn

Пример 3: Активность по часам

bash awk '{print substr($4, 14, 2)}' access.log | sort | uniq -c

Если время в логе в формате [03/Mar/2026:14:23:45, то substr($4, 14, 2) вытащит час (14).

Пример 4: Очистка и подсчёт ошибок в Java-логах

Java-логи часто многострочные. Сначала склеим стектрейсы, потом посчитаем:

bash sed '/^[0-9]/!{:a;N;s/\n/ /;ta}' app.log | grep ERROR | wc -l

Это сложное заклинание, но оно работает: склеивает строки, которые не начинаются с цифры (продолжение стека), с предыдущей строкой.

Реальные кейсы из жизни

Кейс 1: Почистить пароли из лога

Случайно залогировали POST-запрос с паролем. Нужно срочно вычистить все упоминания.

bash sed -i 's/password=[^&]*/password=***/g' access.log

Кейс 2: Посчитать количество уникальных ошибок

В логе приложения ошибки вида ERROR: что-то пошло не так. Хотим понять, какие ошибки самые частые.

bash grep ERROR app.log | sed 's/.*ERROR: //' | sort | uniq -c | sort -rn

Кейс 3: Преобразовать timestamp в другой формат

Было: 2026-03-03 14:23:45 ERROR ... Надо: 03/03/2026 14:23:45 ERROR ...

bash sed -E 's/([0-9]{4})-([0-9]{2})-([0-9]{2})/\3\/\2\/\1/' app.log

Кейс 4: Вытащить все IP из лога (даже если они внутри строки)

bash grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' app.log | sort -u

grep -o выводит только совпадения, а не всю строку.

Полезные однострочники (шпаргалка)

Sed

```bash

Удалить пустые строки

sed '/^$/d' file

Удалить комментарии

sed '/^#/d' file

Заменить табуляцию на пробелы

sed 's/\t/ /g' file

Добавить строку в начало файла

sed '1i\Новая первая строка' file

Удалить последние 5 строк

sed -n ':a;N;$!ba;s/\n/ /g' file # сложно, но работает ```

Awk

```bash

Вывести строки с 10 по 20

awk 'NR>=10 && NR<=20' file

Вывести последнее поле каждой строки

awk '{print $NF}' file

Пропустить первые 10 строк

awk 'NR>10' file

Посчитать сумму чисел во втором поле

awk '{sum+=$2} END {print sum}' file

Вывести строки, где длина больше 80 символов

awk 'length($0) > 80' file ```

Производительность: почему это быстро

Когда вы открываете гигабайтный файл в редакторе, он пытается загрузить его в память целиком. Это убийственно.

Когда вы делаете sed 's/что-то/на что-то/' bigfile.log, происходит следующее: - Файл читается блоками (буферизованно) - Каждый блок обрабатывается - Результат пишется (или выводится) - Память не растёт

Даже на файлах в десятки гигабайт sed и awk будут работать, пока есть место на диске для результата.

Типичные ошибки новичков

Ошибка 1: Забыть про кавычки

```bash

Неправильно

awk {print $1} file

Правильно

awk '{print $1}' file ```

Ошибка 2: Путать $ в awk и $ в shell

Внутри одинарных кавычек переменные shell не подставляются:

```bash

Неправильно (если переменная IP=192.168)

awk '/$IP/' file

Правильно

awk '/'$IP'/' file # закрыли кавычки, вставили переменную, открыли снова ```

Ошибка 3: Игнорировать экранирование

В регулярках много спецсимволов. Точка — любой символ, звёздочка — повторение.

```bash

Неправильно (найдёт "a" и что угодно после)

sed 's/a*/b/' file

Правильно (ищем буквально звёздочку)

sed 's/*/звёздочка/g' file ```

Ошибка 4: Менять файл без проверки

Всегда сначала проверяйте без -i:

bash sed 's/важное/очень важное/' file | head -20

Посмотрели, что всё ок — потом уже -i.

Интерактивный режим: работа с большими файлами

Если нужно "полазить" по огромному файлу, не открывая его целиком:

bash less bigfile.log

В less можно: - /ошибка — найти слово "ошибка" - n — следующее совпадение - N — предыдущее - G — в конец файла - g — в начало - F — следить за обновлениями (как tail -f)

А если нужно посмотреть конкретные строки, sed и awk справятся:

```bash

Показать строки с 1000 по 2000

sed -n '1000,2000p' bigfile.log

Показать строки с 5000 до конца

sed -n '5000,$p' bigfile.log ```

Что дальше?

awk и sed — это только начало. Когда вы освоите их, следующим шагом будут: - jq — для работы с JSON-логами - xpath — для XML-логов - perl — если нужно совсем сложное преобразование

Но для 95% повседневных задач хватает связки grep | sed | awk | sort | uniq.

Коротко: шпаргалка

| Задача | Команда | |--------|---------| | Заменить текст | sed 's/старое/новое/g' | | Удалить строки | sed '/шаблон/d' | | Вырезать колонки | awk '{print $1, $2}' | | Посчитать уникальные | sort \| uniq -c \| sort -rn | | Фильтр по условию | awk '$9 == 500' | | Статистика | awk '{count[$1]++} END {for (i in count) print i, count[i]}' | | Сумма чисел | awk '{sum+=$2} END {print sum}' |

Вместо заключения

Я понимаю, что поначалу awk и sed выглядят как китайская грамота. Слишком много долларов, слешей и фигурных скобок. Но поверьте: это как учиться ездить на велосипеде. Первые полчаса страшно, потом — уже не представляешь жизни без него.

Начните с малого. Сегодня вырежьте IP из лога. Завтра посчитайте топ-10 ошибок. Послезавтра автоматизируйте еженедельный отчёт одной командой.

И никогда больше не открывайте гигабайтные логи в редакторе. Это прошлый век. Настоящие сисадмины смотрят на логи, не открывая файлов. Будьте как настоящие сисадмины.