awk в Linux: обработка табличных данных и логов с примерами
awk — миниатюрный язык программирования для построчной обработки текста. Идеально подходит для работы с таблицами, CSV, логами и любыми данными со столбцами: автоматически разделяет каждую строку на поля и даёт удобный синтаксис фильтрации и преобразования. Разбираем базовый синтаксис, переменные, шаблоны, действия и десяток рецептов для повседневной работы администратора Ubuntu.
Что такое awk и зачем
awk — миниатюрный язык программирования и одновременно утилита Unix, специально заточенная под обработку структурированного текста (таблиц, CSV, логов). Название — аббревиатура имён авторов (Aho, Weinberger, Kernighan).
На Ubuntu по умолчанию установлен gawk (GNU awk) — самая полная реализация. Базовые синонимы:
awk --version # покажет GNU Awk
which awk # обычно /usr/bin/awk → ссылка на gawk
Что умеет awk:
- Автоматически делит строку на поля по разделителю (по умолчанию — пробелы).
- Применяет действия к строкам, удовлетворяющим шаблону.
- Считает суммы, средние, группирует.
- Форматирует вывод через
printf. - Работает как полноценный язык: переменные, массивы, циклы, функции.
Главное преимущество перед grep/sed: awk думает столбцами. Если данные — таблица, awk-однострочник часто короче, чем bash-скрипт с cut, head, tail и арифметикой.
Базовый синтаксис
awk 'pattern { action }' file
Если pattern опущен — действие применяется к каждой строке. Если action опущен — печатается вся строка (как grep).
Самый простой пример:
# Печать первого столбца /etc/passwd (разделитель — двоеточие)
awk -F: '{print $1}' /etc/passwd
-F: — установить разделитель полей в двоеточие. $1 — первое поле, $0 — вся строка, NF — количество полей в строке, $NF — последнее поле.
Поля и разделители
# Все поля /etc/passwd
awk -F: '{print $1, $3, $7}' /etc/passwd
# вывод: root 0 /bin/bash
$0— вся текущая строка.$1,$2, ...$NF— отдельные поля.NF— number of fields, количество полей в текущей строке.NR— number of record, номер текущей строки (с 1).FILENAME— имя текущего обрабатываемого файла.
Разделитель — FS (field separator) на входе и OFS (output field separator) на выходе:
# Заменить разделитель ; на табуляцию
awk -F';' 'BEGIN{OFS="\\t"} {print $1, $2, $3}' input.csv
# CSV с возможными запятыми в значениях — простой не парсер
awk -F',' '{print $1}' file.csv
Для сложных CSV (с экранированными значениями) лучше специализированные инструменты (csvkit, mlr), но для простых данных awk достаточно.
Шаблоны: что фильтровать
Шаблон ставится перед { action }. Если строка ему соответствует — действие выполняется.
Регулярные выражения
# Строки, содержащие ERROR
awk '/ERROR/' /var/log/app.log
# Строки, начинающиеся с #
awk '/^#/' /etc/nginx/nginx.conf
# Несколько условий
awk '/ERROR|FATAL/' app.log
Регулярки в awk — ERE (как у grep -E), без экранирования alternations и групп.
Условия на поля
# Логи с кодом ответа 500 (предположим, $9 — статус)
awk '$9 == 500' /var/log/nginx/access.log
# Файлы тяжелее 1 МБ из ls -l ($5 — размер)
ls -l | awk '$5 > 1048576 {print $9, $5}'
# Только записи с непустым полем 4
awk '$4 != ""' data.txt
BEGIN и END
Специальные шаблоны, выполняемые до первой строки и после последней:
# Подсчитать сумму чисел во втором столбце
awk '{sum += $2} END {print sum}' data.txt
# Среднее значение
awk '{sum += $2; n++} END {print sum / n}' data.txt
# Заголовок таблицы
awk 'BEGIN{print "USER\\tUID"} {print $1, $3}' /etc/passwd
BEGIN особенно полезен для инициализации FS, OFS, объявления переменных. END — для агрегаций.
Диапазоны строк
# Строки между маркерами (включительно)
awk '/<start>/,/<end>/' file.txt
# С номера 10 по 20
awk 'NR >= 10 && NR <= 20' file.txt
Действия
Печатает поля через OFS:
awk '{print $2, $1}' file # поменять местами 1-е и 2-е поля
printf
C-style форматирование:
# Аккуратная таблица
awk '{printf "%-15s %5d\\n", $1, $2}' data.txt
# Конвертация байт в МБ
df | awk 'NR>1 {printf "%-25s %.2f GB\\n", $1, $2/1024/1024}'
Присваивания и переменные
# Подсчитать строки, длиннее 80 символов
awk 'length($0) > 80 {n++} END {print n}' README.md
# Уникальные значения первой колонки (как sort -u)
awk '!seen[$1]++' file.txt
# Сумма по группам (первое поле — ключ)
awk '{sum[$1] += $2} END {for (k in sum) print k, sum[k]}' sales.txt
!seen[$1]++ — классический трюк для дедупликации без sort: использует ассоциативный массив seen, при первом появлении ключа значение становится 1, и !seen[$1]++ возвращает true; на втором появлении — false.
Десять рецептов
# 1. Имена пользователей с UID >= 1000 (обычные пользователи Linux)
awk -F: '$3 >= 1000 {print $1}' /etc/passwd
# 2. Топ-10 IP по запросам в nginx логе
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head
# 3. Сумма размеров файлов в директории
ls -l | awk '{sum += $5} END {print sum/1024/1024 " MB"}'
# 4. Подсчитать строки в файле (без wc)
awk 'END {print NR}' file.txt
# 5. Удалить пустые строки и комментарии
awk '!/^$/ && !/^#/' /etc/nginx/nginx.conf
# 6. Заменить значение в N-м поле
awk -F: 'BEGIN{OFS=":"} {$7="/bin/zsh"; print}' /etc/passwd
# 7. Найти самые длинные строки в файле
awk '{print length($0), NR, $0}' file.txt | sort -rn | head
# 8. Конвертация табов в запятые
awk 'BEGIN{FS="\\t"; OFS=","} {$1=$1; print}' tabbed.txt > csv.txt
# 9. Считать только определённые HTTP-методы в логе
awk '$6 ~ /POST|PUT|DELETE/ {count[$6]++} END {for (m in count) print m, count[m]}' access.log
# 10. Выгрузить middle-колонку (не первую и не последнюю)
awk '{$1=""; $NF=""; print}' file.txt
awk vs sed vs grep
Три похожих инструмента, разные задачи:
| Инструмент | Идеален для | Способ работы |
|---|---|---|
grep |
поиск строк по шаблону | фильтрация |
sed |
замена/удаление подстрок | потоковое редактирование |
awk |
работа со столбцами и арифметика | мини-язык программирования |
Если задача — «найти строки» — grep. «Заменить текст» — sed. «Посчитать что-то по столбцам» — awk.
Часто все три встречаются в одной цепочке:
# Сколько уникальных IP сделало больше 100 запросов
grep "POST /api" /var/log/nginx/access.log \
| awk '{print $1}' \
| sort | uniq -c \
| awk '$1 > 100 {print $2, $1}'
Производительность
awk обрабатывает несколько сот МБ/сек на одно ядро. Для гигабайтных файлов:
- Не используйте регулярки на каждой строке без необходимости — фильтруйте сначала
grep. LANG=C awkускоряет работу на ASCII-данных (без юникода).- Для параллелизма — GNU parallel:
parallel --pipe --block 100M awk '...' < huge.log.
Современный gawk поддерживает многопроцессорный режим с MPFR — но для админских задач обычно хватает однопоточного.
Использование awk как полного языка
В скрипты awk можно вынести через -f:
# script.awk
BEGIN {
FS = ","
OFS = "\\t"
print "USER", "TOTAL"
}
{
sum[$1] += $2
count[$1]++
}
END {
for (user in sum) {
printf "%-20s %d (avg %.2f)\\n", user, sum[user], sum[user]/count[user]
}
}
awk -f script.awk sales.csv
Это уже полноценная аналитика, не однострочник. Когда задача переросла в скрипт на 50+ строк — обычно стоит переходить на Python с pandas; awk — для коротких операций.
Частые вопросы
Чем awk отличается от sed?
awk работает со строкой как с набором полей и поддерживает арифметику, переменные, массивы. sed — потоковый редактор для замены/удаления текста, минимум арифметики. Если задача звучит как «посчитать среднее во втором столбце» — это awk. Если «заменить foo на bar» — это sed.
Как узнать количество полей в строке?
Переменная NF (number of fields) автоматически содержит количество полей в текущей строке. awk '{print NF}' file — для каждой строки выведет своё количество полей. $NF — последнее поле.
Как задать другой разделитель полей?
Через -F в командной строке или присваивание FS в блоке BEGIN. Примеры: awk -F: '...' (двоеточие), awk -F"\\t" '...' (табуляция), awk 'BEGIN{FS=","} ...' (запятая). Для регулярки в качестве разделителя: awk -F'[,;|]' '...'.
Что такое NR и FNR?
NR — глобальный счётчик строк, продолжает считать через файлы. FNR — счётчик внутри текущего файла, сбрасывается при переходе к следующему. Полезно при обработке нескольких файлов: awk 'FNR==1 {print "==> " FILENAME " <=="} {print}' file1 file2.
Можно ли использовать awk для CSV с экранированными запятыми?
Базовый awk — нет, потому что не понимает кавычек. Для простого CSV (без вложенных запятых) — awk -F',' работает. Для сложного — используйте mlr (Miller) или csvkit. Альтернатива — gawk с FPAT: awk 'BEGIN{FPAT="([^,]+)|(\\"[^\\"]+\\")"} ...', но это уже хрупко.
Что запомнить
awk— мини-язык для построчной работы с таблицами и логами.- Базовый синтаксис:
awk 'pattern { action }' file. - Поля доступны как
$1, $2, ..., $NF. Разделитель —-FилиFSв BEGIN. - Переменные:
NR(строка),NF(количество полей),FILENAME. - Специальные шаблоны:
BEGIN(до обработки),END(после), regex/.../, условия на поля. - Действия:
print,printf, присваивания, массивыarr[key]++. - Трюк дедупликации:
awk '!seen[$1]++'. - Связка с grep и sed: grep фильтрует, awk считает по столбцам, sed редактирует.
- Большие задачи переносить в
-f script.awkили Python.