← Весь справочник

awk

Обработка текста по столбцам — выбор полей, фильтры, подсчёты и суммы

awk делит каждую строку на поля и выполняет для неё правила вида условие { действие }. Это небольшой язык с переменными, массивами, функциями и printf, поэтому на нём удобно выбирать столбцы, фильтровать строки по значению поля и считать итоги. В песочнице awk — это GNU awk (gawk) 5.2.

Синтаксис

awk [опции] 'программа' [файл…]
awk [опции] -f программа.awk [файл…]

Программа — набор правил условие { действие }. Для каждой строки ввода awk проверяет правила по порядку. Нет условия — действие выполняется для каждой строки. Нет действия — строка печатается целиком ({print}). Блок BEGIN { … } выполняется до чтения ввода, END { … } — после.

Опции

ОпцияЧто делает
-F раздразделитель полей: символ (-F:), строка или регулярка (-F'[,;]'); -F'\t' — табуляция
-v имя=значениезадать переменную до запуска (можно повторять)
-f файлвзять программу из файла
-e 'текст'добавить кусок программы (вместе с -f)
-i библиотекаподключить файл с функциями (например, -i inplace)
-bсчитать символы как байты
-nраспознавать во входных данных восьмеричные (011) и шестнадцатеричные (0x1F) числа
-Mточная арифметика с большими числами
-P / -cстрогий режим POSIX / режим старого awk без расширений GNU
-Lпредупреждать о сомнительных и непереносимых конструкциях
-dпосле работы вывести все глобальные переменные в awkvars.out
-oкрасиво отформатировать программу в awkprof.out вместо запуска

Присваивание можно написать и среди файлов: awk '…' x=1 file1 x=2 file2 — оно сработает перед чтением следующего файла.

Условия

УсловиеКогда срабатывает
/рег/строка совпадает с регуляркой (ERE)
$3 ~ /рег/ / $3 !~ /рег/поле совпадает / не совпадает
$2 > 10, $1 == "x", NF != 3сравнение; &&, ||, ! — логика
NR == 5, NR > 1по номеру строки
усл1, усл2диапазон: от строки, где верно усл1, до строки, где верно усл2
BEGIN / ENDдо ввода / после ввода

Встроенные переменные

ПеременнаяЧто значит
$0вся текущая строка
$1 … $NFполя; $(NF-1) — предпоследнее
NFчисло полей в строке
NRномер строки, сквозной по всем файлам
FNRномер строки в текущем файле
FILENAMEимя текущего файла
FS / OFSразделитель полей на входе (по умолчанию — пробелы и табуляции) / на выходе (пробел)
RS / ORSразделитель записей на входе / на выходе (по умолчанию \n); RS="" — записи разделены пустыми строками
RSTART / RLENGTHпозиция и длина последнего совпадения match()
ENVIRON["HOME"]переменные окружения
IGNORECASE=1сравнивать регулярки без учёта регистра (gawk)

Язык

  • Действия: print a, b (через OFS), printf "формат", a, b (как в C, без перевода строки в конце), присваивания = += -= ++, if (…) … else …, while, for (i = 1; i <= NF; i++), for (k in массив), next (к следующей строке), exit, delete массив[k].
  • Массивы ассоциативные: cnt[$1]++, проверка ключа — if ("x" in cnt).
  • Вывод можно перенаправить: print > "файл", print >> "файл", print | "sort".
  • Строки склеиваются простым соседством: x = $1 "-" $2.

Функции

ФункцияЧто делает
length(s)длина строки (без аргумента — $0); для массива — число элементов
substr(s, i, n)подстрока с позиции i (с 1) длиной n
index(s, t)позиция t в s, 0 — если нет
split(s, a, разд)разбить s в массив a, вернуть число частей
sub(/рег/, "з", s) / gsub(…)заменить первое / все вхождения в s (по умолчанию в $0); & в замене — совпадение
gensub(/рег/, "з", "g", s)как gsub, но возвращает результат и понимает \\1 (gawk)
match(s, /рег/, a)найти совпадение, заполнить RSTART, RLENGTH и группы в a (gawk)
tolower(s) / toupper(s)регистр
sprintf(формат, …)как printf, но вернуть строку
int(x), sqrt(x), rand()целая часть, корень, случайное число
system("команда")запустить команду оболочки
strftime("%F", t), systime()дата и текущее время (gawk)
asort(a), asorti(a)отсортировать массив по значениям / по ключам (gawk)

Примеры

printf 'alice 30 dev\nbob 25 ops\ncarol 35 dev\n' > people.txt

# первый и последний столбец
awk '{print $1, $NF}' people.txt

# фильтр по значению поля и по регулярке
awk '$3 == "dev" {print $1, $2}' people.txt
awk '$2 > 28' people.txt
awk '$1 ~ /^c/' people.txt

# пропустить первую строку (заголовок)
awk 'NR > 1' people.txt

# сумма, среднее, максимум
awk '{s += $2} END {print s, s / NR}' people.txt
awk 'NR == 1 || $2 > max {max = $2} END {print max}' people.txt

# подсчёт по группам (ассоциативный массив)
awk '{c[$3]++} END {for (k in c) print k, c[k]}' people.txt

# сумма по группам
awk '{s[$3] += $2} END {for (k in s) print k, s[k]}' people.txt

# первая строка для каждого значения поля — дубли отбрасываются
awk '!seen[$3]++' people.txt

# другой разделитель на входе и на выходе
echo 'a:b:c' | awk -F: -v OFS=- '{$1 = $1; print}'
printf 'id,name\n1,alice\n' | awk -F, '{print $2}'

# форматированный вывод
awk '{printf "%-6s %3d\n", $1, $2}' people.txt

# передать значение из оболочки
min=30
awk -v min="$min" '$2 >= min {print $1}' people.txt

# поменять столбцы местами
awk '{print $2, $1}' people.txt

# замена внутри поля и вывод
awk '{gsub(/a/, "A", $1); print $1}' people.txt

# группа регулярки (gawk): вытащить число из строки
echo 'took 125ms' | awk 'match($0, /([0-9]+)ms/, m) {print m[1]}'

# строки, где не 3 поля, — с номерами
printf 'a b c\nd e\n' | awk 'NF != 3 {print NR": "$0}'

# объединить два файла по первому полю: сначала читаем первый в массив
printf 'alice admin\nbob user\n' > roles.txt
awk 'FNR == NR {role[$1] = $2; next} {print $1, role[$1]}' roles.txt people.txt

Подводные камни

  • Программу пиши в одинарных кавычках. В двойных оболочка подставит $1 сама (обычно пустоту), и awk "{print $1}" напечатает строки целиком.
  • Переменные оболочки внутри '…' не видны. Передавай их через -v, а не склеивая кавычки.
  • Строка или число. $1 > "9" — сравнение строк, и 10 окажется «меньше» 9. Сравнивай с числом без кавычек: $1 > 9.
  • По умолчанию разделитель — любая цепочка пробелов и табуляций, а пробелы в начале строки игнорируются (-F' ' означает то же самое). С любым другим разделителем пустые поля сохраняются: с -F, в a,,b три поля, и $3 — это b; с -F'\t' две табуляции подряд тоже дают пустое поле.
  • OFS применяется, только когда строка пересобирается. print без изменений выведет $0 как было; присвой любое поле ($1 = $1), чтобы строка собралась заново с новым разделителем.
  • print $1 $2 склеивает поля без пробела. Запятая (print $1, $2) вставляет OFS.
  • printf не добавляет перевод строки — пиши \n в формате.
  • Порядок в for (k in массив) не определён. Если нужен порядок — отсортируй вывод через sort.
  • Обратных ссылок \1 в регулярках awk нет. Для групп используй match(…, …, массив) или gensub.
  • Локаль. В песочнице локаль POSIX, поэтому length() и substr() считают байты: у пр длина 4, а toupper не трогает кириллицу. С LC_ALL=C.utf8 считаются символы.

См. также

sed · grep · cut · sort · datamash · Регулярные выражения