linux streams

awk

Языковый процессор для поиска и обработки текстовых данных по шаблонам

Описание

awk — мощный язык программирования и утилита для обработки текстовых файлов. Создан в 1977 году Альфредом Ахо (A), Питером Вайнбергером (W) и Брайаном Керниганом (K) в Bell Labs — отсюда название. awk автоматически разбивает каждую строку на поля, предоставляет встроенные переменные и поддерживает управляющие конструкции языка C.

Программа awk состоит из правил вида шаблон { действие }. Для каждой входной строки awk проверяет шаблон — если он совпадает, выполняется действие. Специальные правила BEGIN и END выполняются до и после обработки всех строк. Поля строки доступны как $1, $2, ..., $NF; вся строка — $0.

Существуют несколько реализаций: оригинальный awk, расширенный gawk (GNU awk, наиболее распространён в Linux) и mawk (быстрый). В большинстве систем awk является псевдонимом для одной из них. gawk добавляет массивы, сетевые возможности, функции и поддержку Unicode.

Синтаксис

awk [OPTIONS] 'program' [FILE...] awk [OPTIONS] -f progfile [FILE...]
# Вывести второе поле awk '{print $2}' file.txt # Строки длиннее 80 символов awk 'length > 80' file.txt # Сумма значений первого поля awk '{sum += $1} END {print sum}' numbers.txt # Разделитель ':' — вывести поля 1 и 3 awk -F: '{print $1, $3}' /etc/passwd

Флаги, опции и встроенные переменные

Флаг / Переменная Описание Пример
-F SEP Установить разделитель полей (FS) awk -F: '{print $1}' /etc/passwd
-v VAR=VAL Установить переменную перед выполнением программы awk -v OFS=, '{print $1,$2}' f
-f FILE Читать программу из файла awk -f script.awk data.txt
$0 Вся текущая строка awk '{print $0}' file
$1, $2, ... Поля строки по порядку awk '{print $1, $3}' file
$NF Последнее поле строки awk '{print $NF}' file
NR Номер текущей записи (строки) awk 'NR==5' file
NF Количество полей в текущей строке awk '{print NF, $0}' file
FS Разделитель входных полей (Field Separator) awk 'BEGIN{FS=","} {print $2}'
OFS Разделитель выходных полей (Output Field Separator) awk 'BEGIN{OFS="|"} {print $1,$2}'
RS Разделитель записей (Record Separator, по умолчанию \n) awk 'BEGIN{RS="\n\n"}' file
FILENAME Имя текущего обрабатываемого файла awk '{print FILENAME, NR}' *.log

Паттерны использования

Вычисления и агрегация

# Сумма и среднее числового поля
awk '{sum+=$1; count++} END {print "Sum:", sum, "Avg:", sum/count}' numbers.txt

# Максимальное значение
awk 'NR==1{max=$1} $1>max{max=$1} END{print max}' file

Фильтрация строк

# Строки с условием по полю
awk '$3 > 100' data.txt
awk '$1 == "ERROR"' log.txt

# С регулярным выражением
awk '/pattern/' file
awk '!/comment/' config.txt   # без комментариев

Форматированный вывод

awk '{printf "%-20s %5d\n", $1, $2}' data.txt

# Заголовок и данные
awk 'BEGIN{printf "%-10s %s\n","Name","Value"}
     {printf "%-10s %s\n",$1,$2}' data.txt

Подсчёт с группировкой

# Частота слов
awk '{for(i=1;i<=NF;i++) count[$i]++}
     END{for(w in count) print count[w], w}' text.txt | sort -rn

Обработка CSV / изменение полей

# Поменять порядок колонок
awk -F',' '{print $2","$1","$3}' data.csv

# Добавить вычисляемое поле
awk -F',' '{print $0","$2*$3}' prices.csv

Многострочная обработка

# BEGIN и END
awk 'BEGIN{print "Start"}
     {total += $1}
     END{print "Total:", total}' nums.txt

# Нумерация строк
awk '{print NR": "$0}' file.txt

Советы и предупреждения

Совет: Используйте -v OFS=',' для изменения разделителя вывода: awk -F: -v OFS=',' '{print $1,$3,$6}' /etc/passwd — конвертирует из формата passwd в CSV.
Совет: Массивы awk — ассоциативные (хэш-таблицы). Используйте их для группировки: awk '{count[$1]++} END{for(k in count) print k, count[k]}' log
Совет: Для простой замены используйте sub() и gsub(): awk '{gsub(/old/, "new"); print}' file — заменить все вхождения в каждой строке.
Внимание: Разделитель полей FS работает как regex. Если используете символы с особым значением в regex (., +, *), экранируйте их: awk -F'\.' для точки.
Внимание: В awk строки и числа автоматически преобразуются. "10" > "9" в строковом сравнении даст false (лексикографически «1» < «9»), поэтому для чисел используйте +0: $1+0 > 9.