open atlas
↑ К треку
Командная строка CLI · 06 · 04

основы awk

awk разбивает строки на поля $1..$NF. NR — счётчик записей, NF — количество полей. Пары шаблон/действие выполняются избирательно. BEGIN инициализирует, END выводит итоги. Ассоциативные массивы считают и суммируют по ключам за один проход.

CLI Middle ◷ 25 min
Уровень
ОсновыJuniorMiddleSenior

cut извлекает колонки. sort | uniq -c их подсчитывает. sed переписывает. Но ни одна из этих утилит не может сложить столбец чисел, вычислить соотношение или вывести итоговую строку после обработки всего ввода. awk может. Это полноценный мини-язык, построенный вокруг идеи, что текст — поток записей (по умолчанию строк), каждая из которых разбита на поля ($1, $2, … $NF). Для каждой записи awk вычисляет список пар шаблон/действие: если шаблон совпадает, выполняется действие. Блок BEGIN устанавливает состояние до любого ввода; блок END подводит итоги после. Эта модель покрывает 80% анализа логов на лету, генерации отчётов и трансформации данных в одной команде.

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

Цель

После этого урока ты сможешь обращаться к полям записи через $1$NF, использовать встроенные переменные NR и NF, писать пары шаблон { действие }, использовать BEGIN для инициализации и END для вывода итогов, задавать пользовательский разделитель полей с -F и накапливать числовые суммы по записям.

1

awk разбивает каждую строку на поля $1, $2, … $NF. По умолчанию разбиение идёт по пробельным символам (любой набор пробелов или табуляций). $0 — вся строка; $NF — последнее поле независимо от их количества; $(NF-1) — предпоследнее.

echo "alice  admin  1024" | awk '{print $1, $3}'
# alice 1024

Запятая в print $1, $3 выводит поля, разделённые выходным разделителем полей (по умолчанию пробел). Без запятой — print $1 $3 — поля конкатенируются без разделителя.

-F задаёт пользовательский разделитель входных полей:

awk -F: '{print $1, $7}' /etc/passwd

Разбивает по : вместо пробелов. Теперь $1 — имя пользователя, $7 — оболочка — те же колонки, что извлекает cut -d: -f1,7, но с куда большими возможностями в действии.

2

NR — номер текущей записи (строки); NF — количество полей в текущей записи.

awk '{print NR, NF, $0}' /etc/passwd | head -3
# 1 7 root:x:0:0:root:/root:/bin/bash
# 2 7 daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
# 3 7 bin:x:2:2:bin:/bin:/usr/sbin/nologin

NR полезен для: пропуска заголовков (NR > 1), вывода каждой N-й строки (NR % 10 == 0), нумерации строк вывода.

NF полезен для: обнаружения некорректных строк (NF != 7), доступа к последнему полю ($NF), или фильтрации строк с минимальным количеством колонок.

# Пропустить заголовок CSV (строка 1) и вывести строки ровно с 5 полями
awk -F, 'NR > 1 && NF == 5 {print $2, $4}' data.csv
3

Пары шаблон/действие: шаблон { действие }. Шаблон — любое выражение; действие выполняется только когда шаблон истинен. Любая из частей необязательна:

  • Без шаблона: действие выполняется для каждой записи.
  • Без действия: действие по умолчанию — {print $0} — вывести всю строку.
# Вывести строки, где поле 3 (размер ответа) > 10000
awk '$3 > 10000 {print $1, $3}' access.log

# Вывести строки, содержащие 'ERROR' (шаблон — регулярное выражение)
awk '/ERROR/ {print NR, $0}' app.log

# Вывести строки, НЕ совпадающие с шаблоном
awk '!/DEBUG/' app.log

В одной программе awk можно иметь несколько пар шаблон/действие — awk вычисляет каждую пару для каждой записи, выполняя все совпадающие действия по порядку. Это отличается от if/else: несколько шаблонов могут совпасть с одной записью.

4

Блоки BEGIN и END выполняются один раз — до и после всего ввода.

  • BEGIN { ... } — инициализировать переменные, вывести заголовок, задать FS (разделитель полей).
  • END { ... } — вывести итоги, средние значения, сводки.
awk 'BEGIN { total = 0 }
     { total += $3 }
     END { print "Total bytes:", total }' access.log

total инициализируется в 0 в BEGIN. Для каждой строки total += $3 накапливает третье поле. После всех строк END выводит итог. Это шаблон аккумулятора awk — без промежуточной сортировки и внешних инструментов.

Задание FS в BEGIN эквивалентно -F:

awk 'BEGIN { FS = ":" } { print $1, $7 }' /etc/passwd
5

Объединение шаблонов, аккумуляторов и END для настоящих сводок.

# Подсчитать строки по HTTP-коду в логе nginx
awk '{status[$9]++}
     END { for (code in status) print status[code], code }' access.log \
  | sort -rn

status[$9]++ использует $9 (поле кода состояния) как ключ ассоциативного массива и увеличивает его счётчик. После всего ввода END итерирует массив с for (ключ in массив) и выводит каждый код со счётчиком. Пайп в sort -rn даёт ранжированную таблицу.

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

awk '{count[$9]++; total[$9]+=$10}
     END { for (c in count) printf "%s  avg=%.0f\n", c, total[c]/count[c] }' access.log

Два параллельных массива, один проход по файлу. Это шаблон, для которого обычно тянешься к pandas или SQL; awk справляется за одну строку.

Разбор примера

Вычислить суммарную и среднюю длительность запросов из лога, где поле 5 — длительность в миллисекундах.

awk 'NR > 1 && $5 ~ /^[0-9]+$/ {
       sum += $5
       count++
     }
     END {
       if (count > 0)
         printf "Запросов: %d  Итого: %dms  Среднее: %.1fms\n", count, sum, sum/count
       else
         print "Нет валидных записей"
     }' requests.log

NR > 1 пропускает строку заголовка. $5 ~ /^[0-9]+$/ проверяет, что поле 5 — чистое целое число перед прибавлением (защита от некорректных строк, где поле равно - или пусто). printf форматирует вывод точно. Блок END защищает от деления на ноль.

Этот шаблон — фильтр-защита в теле, итоги в END — является продакшн-качественной awk-идиомой для числовой агрегации.

Почему это работает

На macOS системный awk — это оригинальный one-true-awk (BSD awk), а не GNU awk (gawk). Для шаблонов в этом уроке — $1$NF, NR, NF, BEGIN, END, ассоциативные массивы, printf — оба ведут себя идентично. Отличия появляются только с продвинутыми возможностями gawk (OFMT, FIELDWIDTHS, gensub()). Для скриптов, требующих расширений gawk, устанавливай его явно (brew install gawk) и вызывай как gawk. Все примеры здесь совместимы с обоими.

Частая ошибка

Самые распространённые ошибки awk: (1) программа awk без одинарных кавычек в оболочке — всегда оборачивай программу awk в одинарные кавычки, чтобы оболочка не интерпретировала $1, { и } до того, как awk их увидит; (2) использование == для сравнения чисел, хранящихся как строки — awk автоматически приводит строки к числам в числовом контексте, поэтому $3 > 10 работает корректно даже когда $3 — строка; но $3 == "10" и $3 == 10 могут различаться при наличии пробелов; (3) забыть END при накоплении — переменные в теле накапливаются корректно, но никогда не выводятся без блока END.

Проверь себя
Викторина

Ты запускаешь: awk 'END {print NR}' file.txt. Что это выводит?

Итог

awk обрабатывает текст как записи, разбитые на поля $1$NF. $0 — вся запись; NR — текущий номер строки; NF — количество полей. -F РАЗД задаёт разделитель входных полей. Пары шаблон/действие выполняются избирательно — /regex/, числовые сравнения или булевы выражения как шаблоны. BEGIN инициализирует переменные и заголовки до ввода; END выводит итоги после всего ввода. Ассоциативные массивы (arr[ключ]++) позволяют подсчитывать и суммировать по ключам за один проход. awk — правильный инструмент, когда нужна арифметика, условная логика или структурированный вывод, которые не могут выразить cut, sort и sed по отдельности.

Практика

Начни сверху. Задачи идут от простого к сложному: вспомнить факт, применить к случаю, затем senior-уровень. Открой, попробуй, потом открой ответ.

вспомнитьприменитьуглубить0 из 4 завершено

Что-то непонятно?

Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.

хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources2
expand
  1. 01
  2. 02

Trademarks belong to their respective owners. Editorial reference only.