Что такое 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 # то же самое
Поля: 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: счётчики
Базовый набор для большинства задач.
# Вывести номер и текст:
$ 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 может быть:
- Regex в
/.../:/ERROR/ { ... }— строки с ERROR - Expression:
$3 > 100 { ... }— строки где 3-е поле > 100 - Range:
/start/,/end/ { ... }— диапазон между двумя regex (как в sed) - BEGIN / END: специальные блоки
- 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.
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 и printf
# 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.
Попробуй сам
- Базовое — вывести колонки:
echo "alice 30 USA" | awk '{print $1, $3}' - Поменять delimiter:
echo "alice:30:USA" | awk -F':' '{print $1}' - Подсчёт строк (как wc -l):
awk 'END {print NR}' /etc/passwd - Сумма чисел:
seq 1 100 | awk '{sum+=$1} END {print sum}' # -> 5050 - Фильтр + 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команда.
Главное
- 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.