Learning Platform
Глоссарий Troubleshooting
Урок 09.03 · 28 мин
Средний
awkPattern-actionFieldsNRNFBEGINEND

Что такое awk

awk — это программируемый text-processor, занимающий нишу между sed (substitution) и Python (full programming). Назван по инициалам авторов: Aho, Weinberger, Kernighan (Bell Labs, 1977). На macOS обычно BSD awk (one-true-awk), на Linux — gawk (GNU awk, более фичерный).

Главная идея awk — pattern-action engine:

PATTERN { ACTION }
PATTERN { ACTION }
PATTERN { ACTION }

Для каждой строки input awk проверяет каждый PATTERN. Если совпадает — выполняет связанный ACTION. Без PATTERN — ACTION выполняется на каждой строке. Без ACTION — default это {print}.

# Эквиваленты:
$ awk '{print}' file              # ACTION на каждой строке
$ awk '1 {print}' file            # PATTERN=1 (всегда true) + ACTION
$ awk '{print $0}' file           # явный $0 = вся строка
$ cat file                         # то же самое 

Поля: 0,0, 1, $2, …

awk автоматически разделяет каждую строку на поля по whitespace (по умолчанию):

$ echo "alice 42 USA" | awk '{print $1, $3}'
alice USA
  • $0 — вся строка
  • $1 — первое поле
  • $2 — второе и т.д.
  • $NF — последнее поле (NF = Number of Fields)
$ echo "a b c d e" | awk '{print $NF, NF}'
e 5

Whitespace по умолчанию = «один или несколько space или tab». То есть "a b" (тройной пробел) = два поля, $1=a, $2=b. Это отличается от cut, где каждый пробел был бы separator.

Изменение разделителя: -F

$ echo "a,b,c" | awk -F',' '{print $2}'
b

$ echo "user:x:1000" | awk -F':' '{print $1, $3}'
user 1000

-F указывает field separator. Это regex, не просто символ:

# Множественные разделители (запятая ИЛИ точка-с-запятой)
$ echo "a,b;c" | awk -F'[,;]' '{print $1, $2, $3}'
a b c

Внутри awk-программы FS — переменная:

$ awk 'BEGIN {FS=","} {print $2}' data.csv

NR и NF: счётчики

Built-in переменные awk

Базовый набор для большинства задач.

NRNumber of Records — номер текущей строкиНачинает с 1. После END содержит общее количество строк прочитанных awk. Можно использовать как 'sed N'd' analog'.
NFNumber of Fields — количество полей в текущей строке$NF — последнее поле. $(NF-1) — предпоследнее.
$0вся текущая строка
$1..$Nполя
FSInput Field SeparatorDefault — whitespace (' '). Через -F или BEGIN{FS=...}.
OFSOutput Field SeparatorDefault ' '. Используется при print со списком через запятую: 'print $1, $2' выводит '$1<OFS>$2'.
RSRecord Separator (default \\n)Можно изменить чтобы awk разделял input по другому символу. Например RS='\\0' для null-separated файлов из find -print0.
ORSOutput Record Separator (default \\n)print автоматически добавляет ORS в конце.
FILENAMEимя текущего входного файла
# Вывести номер и текст:
$ awk '{print NR, $0}' file
1 first line
2 second line
3 third line

# Сколько полей в каждой строке:
$ echo -e "a b c\nd e\nf g h i" | awk '{print NF}'
3
2
4

BEGIN и END блоки

  • BEGIN — выполняется до чтения входа. Инициализация переменных, заголовки.
  • END — выполняется после всех строк. Финальные вычисления, суммы.
$ awk 'BEGIN {print "Start"; sum=0} {sum+=$1} END {print "Sum:", sum}' numbers.txt
Start
Sum: 1234

Это сразу даёт мощь sql-aggregations:

# Сумма колонки 3 в CSV
$ awk -F',' '{sum+=$3} END {print sum}' orders.csv
12345.67

# Среднее
$ awk -F',' '{sum+=$3; n++} END {print sum/n}' orders.csv

# Min/max
$ awk -F',' '{if (NR==1 || $3<min) min=$3; if ($3>max) max=$3} END {print min, max}' file

PATTERN options

PATTERN может быть:

  1. Regex в /.../: /ERROR/ { ... } — строки с ERROR
  2. Expression: $3 > 100 { ... } — строки где 3-е поле > 100
  3. Range: /start/,/end/ { ... } — диапазон между двумя regex (как в sed)
  4. BEGIN / END: специальные блоки
  5. Combo: NR > 1 && $3 > 100 — комбинирование условий
# Только ERROR-строки, выведем dag_id
$ awk -F'dag_id=' '/ERROR/ {print $2}' app.log

# Только rows где amount > 1000 (3-я колонка)
$ awk -F',' '$3 > 1000' orders.csv

# Skip header (первая строка) и выведем 2-ю колонку
$ awk -F',' 'NR > 1 {print $2}' data.csv

$3 > 1000 без действия — это PATTERN. Default ACTION для совпадений — {print} — то есть выводится вся строка.

DE-сценарии

1. SQL-like aggregation

# Sum amounts по country
$ awk -F',' 'NR > 1 {sums[$5] += $3} END {for (c in sums) print c, sums[c]}' orders.csv
USA 12345.67
France 8910.50
Germany 6789.00

Это эквивалент SELECT country, SUM(amount) FROM orders GROUP BY country.

GROUP BY и агрегации в SQL — SUM по группам

2. Подсчёт по условию

# Сколько строк с status=200
$ awk '$9 == 200' access.log | wc -l

# Топ-5 IP по числу запросов
$ awk '{ips[$1]++} END {for (ip in ips) print ips[ip], ip}' access.log \
    | sort -rn | head -5

3. Фильтр + transform одной командой

# Из логов выбрать ERROR-строки, вывести только timestamp + msg
$ awk '/ERROR/ {print $1, $2, $4, $5, $6}' app.log

4. Подсчёт уникальных значений

# Сколько уникальных users
$ awk -F',' 'NR > 1 {users[$2]=1} END {print length(users)}' orders.csv

length(array) возвращает количество ключей в associative array — GNU awk поддерживает (POSIX awk не имел этого, требовал ручной счётчик).

5. Самый длинный лог-message

$ awk '{if (length($0) > maxlen) {maxlen=length($0); maxline=$0}} END {print maxline}' app.log
# print со списком — разделяет OFS (default space):
$ awk '{print $1, $3}'
# Эквивалент:
$ awk '{print $1 OFS $3}'

# printf — точное форматирование (без auto \n):
$ awk -F',' '{printf "%-20s %10.2f\n", $1, $3}' orders.csv
alice                  150.00
bob                    230.50

printf — как в C/Python: %s строка, %d decimal, %f float, %-20s left-align с шириной 20, %10.2f 10 символов, 2 после точки.

awk vs gawk vs mawk

  • POSIX awk — минимум, портабельно, мало фич
  • gawk — GNU awk, дополнительно: length(array), gensub(), strftime(), asort(), getline networking, и больше
  • mawk — minimalist awk, быстрее gawk на простых задачах
  • BSD awk (one-true-awk) — на macOS по умолчанию

В Ubuntu 26.04 по умолчанию mawk через alternatives, можно установить gawk для full feature set:

$ sudo apt install gawk
$ which awk
/usr/bin/awk  -> /etc/alternatives/awk -> /usr/bin/gawk

Для cross-platform скриптов используй POSIX-подмножество. Если нужны GNU-only фичи (gensub, length(arr)) — явно вызывай gawk или mawk.

Попробуй сам

  1. Базовое — вывести колонки:
    echo "alice 30 USA" | awk '{print $1, $3}'
  2. Поменять delimiter:
    echo "alice:30:USA" | awk -F':' '{print $1}'
  3. Подсчёт строк (как wc -l):
    awk 'END {print NR}' /etc/passwd
  4. Сумма чисел:
    seq 1 100 | awk '{sum+=$1} END {print sum}'
    # -> 5050
  5. Фильтр + projection:
    awk -F':' '$3 < 100 {print $1, $3}' /etc/passwd
    # имена system-users с UID < 100

macOS-различия

  • BSD awk на macOS:
    • Базовый POSIX-функционал работает идентично
    • Не поддерживает length(array) (используй счётчик ++)
    • Не поддерживает gensub() — используй gsub() (заменяет in-place в $0 или указанной переменной)
    • Не поддерживает FIELDWIDTHS (фиксированные позиции для COBOL-like форматов)
  • Для GNU-фич — brew install gawk -> gawk команда.
Проверка знанийKnowledge check
Команда 'awk -F,' \"{print NR, NF, $0}\" data.csv' — что выведет каждая строка? Допустим, data.csv = '1,2,3\n4,5\n6,7,8,9'.
ОтветAnswer
Выведет три строки: '1 3 1,2,3', '2 2 4,5', '3 4 6,7,8,9'. Объяснение: NR — Number of Record, номер строки начиная с 1; NF — Number of Fields, количество полей в текущей строке; $0 — вся строка. Для первой строки '1,2,3': NR=1, NF=3 (три поля: 1, 2, 3), $0='1,2,3'. Для второй '4,5': NR=2, NF=2. Для третьей '6,7,8,9': NR=3, NF=4. -F',' указывает запятую как field separator (вместо whitespace по умолчанию). Замечание: $0 содержит исходную строку как она была прочитана (с любыми разделителями). Если awk модифицировал какое-то $N в action, $0 автоматически перестроится с использованием OFS (а не FS) — это часто причина 'почему мой output имеет другие разделители'. Чтобы output был с тем же FS: 'BEGIN {OFS=FS} {...; print}' или 'BEGIN{OFS=FS=','}'.

Главное

  • awk — pattern-action engine: PATTERN { ACTION }. Без PATTERN — на каждой строке. Без ACTION — {print}.
  • Поля: $0 (whole), $1, $2, ..., $NF. Разделитель: default whitespace, -F',' для CSV.
  • Переменные: NR (line number), NF (num fields), FS/OFS (in/out separator).
  • BEGIN { ... } до input, END { ... } после — для инициализации и финальных вычислений.
  • PATTERN может быть: regex /.../, expression $3 > 100, range /a/,/b/, или комбинация &&/||.
  • print использует OFS, printf — точное форматирование как в C.
  • Associative arrays arr[key] — для group-by aggregation.
  • gawk на Linux, mawk минималистичный, BSD awk на macOS — для cross-platform stick to POSIX.

Проверьте понимание

Результат: 0 из 0
Концептуальный
Вопрос 1 из 4. В awk что означает '$NF' и чем отличается от '$1'?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 5