
Среди многочисленных инструментов обработки текста, доступных в оболочке Linux, awk выделяется своей мощью и универсальностью. Разработанный в 1970-х годах Ахо, Вайнбергером и Керниганом, awk — это больше, чем просто команда, это незаменимый инструмент в арсенале системного администратора и DevOps инженера. Она позволяет за секунды решать задачи которые потребовали бы десятков строк кода на других языках, это полноценный язык программирования, предназначенный для обработки и анализа текстовых файлов.
Основные преимущества awk: работа со структурированными данными по столбцам, встроенная поддержка регулярных выражений, математические вычисления, минималистичный синтаксис для простых задач и возможность создания сложных программ для продвинутых сценариев.
Изучив базовые концепции из этого руководства вы сможете: анализировать лог-файлы веб-серверов и приложений, обрабатывать CSV и другие табличные данные, автоматизировать рутинные операции с текстом, мониторить системные ресурсы и строить отчеты.
Команда awk
awk работает с файлами и потоками как с последовательностью записей и полей. По умолчанию запись определяется как строка, а поля разделяются пробелами, хотя и то и другое может быть переопределено.
Основной синтаксис
Основной синтаксис awk следующий:
awk ‘pattern {action}’ file
- Шаблон: Указывает, когда должно быть выполнено действие. Если это значение опущено, действие применяется к каждой строке.
- Действие: Набор команд, выполняемых при совпадении с шаблоном. Действия заключаются в фигурные скобки {}.
Базовая структура:
awk 'pattern {action}' файл
- pattern — условие отбора строк (опционально)
- action — действие над строками которые соответствуют условию
- файл — входной файл (можно несколько или stdin через pipe)
Примеры awk
Основные варианты использования:
Печать всех строк (как cat):
awk '{print}' file.txt
Печать первого столбца:
awk '{print $1}' file.txt
Строки содержащие «error»:
awk '/error/ {print}' file.txt
С условием на значение столбца:
awk '$3 > 100 {print $1, $3}' file.txt
Несколько действий через точку с запятой:
awk '{sum += $2; count++} END {print sum/count}' file.txt
Сумма и среднее значение столбца
awk ‘{sum+=$2; count++} END {print «Sum =», sum; print «Average =», sum/count}’ file.txt
Эта команда вычисляет сумму и среднее значение значений во втором столбце файла file.txt.
Фильтрация на основе условия
awk ‘$3 > 100’ file.txt
Здесь отображаются строки из файла file.txt, в которых третье поле больше 100.
Важные опции командной строки:
| Опция | Описание | Пример |
|---|---|---|
-F | Указать разделитель полей | awk -F':' '{print $1}' /etc/passwd |
-v | Передать переменную в программу | awk -v limit=100 '$3 > limit' |
-f | Читать программу из файла | awk -f script.awk data.txt |
Разделители полей:
По умолчанию awk разбивает строки по пробелам и табуляциям. Для других разделителей:
CSV файл (запятая):
awk -F',' '{print $1, $3}' data.csv
Файл /etc/passwd (двоеточие):
awk -F':' '{print $1, $6}' /etc/passwd
Несколько символов разделителей:
awk -F'[,:]' '{print $1}' mixed.txt
Регулярное выражение как разделитель:
awk -F'[[:space:]]+' '{print $1}' file.txt
Запись (Record) — строка входного текста. Awk обрабатывает файл построчно.
Поле (Field) — столбец в записи, разделенный специальным символом.
Обозначение полей:
$0— вся строка целиком$1— первое поле (первый столбец)$2— второе поле$NF— последнее поле (NF= number of fields)$(NF-1)— предпоследнее поле
Пример данных (employees.txt):
John Manager Sales 5000
Alice Developer IT 6000
Bob Analyst Finance 4500
Работа с полями:
Печать имени и зарплаты
awk '{print $1, $4}' employees.txt
Переставить столбцы местами
awk '{print $4, $2, $1}' employees.txt
Конкатенация строк
awk '{print $1 " работает в " $3}' employees.txt
Арифметика
awk '{print $1, $4 * 1.15}' employees.txt
Паттерны определяют какие строки обрабатывать.
Типы паттернов:
1. Регулярные выражения (между слэшами):
Печатает строки содержащие «IT»:
awk '/IT/ {print}' employees.txt
2. Сравнение полей:
Печатает сотрудников с зарплатой > 5000:
awk '$4 > 5000 {print $1, $4}' employees.txt
3. Логические операторы:
Оператор И (AND) — отдел Sales И зарплата > 4000:
awk '$3 == "Sales" && $4 > 4000 {print}' employees.txt
Оператор ИЛИ (OR) — зарплата < 5000 ИЛИ должность Manager:
awk '$4 < 5000 || $2 == "Manager" {print}' employees.txt
4. Диапазоны строк:
Печатает строки от паттерна START до END включительно:
awk '/START/,/END/ {print}' file.txt
5. Отрицание:
Все кроме отдела IT:
awk '$3 != "IT" {print}' employees.txt
Строки НЕ содержащие Manager:
awk '!/Manager/ {print}' employees.txt
Операторы сравнения:
| Оператор | Значение | Пример |
|---|---|---|
== | Равно | $1 == "John" |
!= | Не равно | $2 != "Sales" |
< | Меньше | $3 < 100 |
> | Больше | $3 > 1000 |
<= | Меньше или равно | $3 <= 50 |
>= | Больше или равно | $3 >= 100 |
~ | Соответствует regex | $1 ~ /^A/ |
!~ | Не соответствует regex | $1 !~ /test/ |
BEGIN — выполняется один раз перед обработкой данных
END — выполняется один раз после обработки всех данных
Заголовок и итог
awk 'BEGIN {print "Имя\tЗарплата"}
{print $1, $4}
END {print "---\nВсего сотрудников:", NR}' employees.txt
Практический пример — вычисление среднего:
awk 'BEGIN {sum=0; count=0}
{sum += $4; count++}
END {print "Средняя зарплата:", sum/count}' employees.txt
Awk предоставляет набор предопределенных переменных для работы с данными.
| Переменная | Описание | Пример использования |
|---|---|---|
NR | Number of Records — номер текущей строки | {print NR, $0} |
NF | Number of Fields — количество полей в строке | {print $NF} (последнее поле) |
FS | Field Separator — разделитель входных полей | BEGIN {FS=":"} {print $1} |
OFS | Output Field Separator — разделитель выходных полей | BEGIN {OFS=","} {print $1, $2} |
RS | Record Separator — разделитель входных записей | BEGIN {RS=";"} {print} |
ORS | Output Record Separator — разделитель выходных записей | BEGIN {ORS="---\n"} {print} |
FILENAME | Имя текущего обрабатываемого файла | {print FILENAME, $0} |
FNR | Номер строки в текущем файле | {print FILENAME, FNR, $0} |
Примеры использования:
Нумерация строк
awk '{print NR, $0}' file.txt
Вывод количества полей в каждой строке
awk '{print "Строка", NR, "содержит", NF, "полей"}' data.txt
Изменение разделителя вывода
awk 'BEGIN {OFS=" | "} {print $1, $2, $3}' file.txt
Обработка нескольких файлов
awk '{print FILENAME, FNR, $1}' file1.txt file2.txt
Базовые операции: + — * / % (остаток от деления)
awk '{print $1, $2 * 1.2}' file.txt
Увеличение значения
awk '{$4 = $4 * 1.15; print}' employees.txt
Накопление суммы
awk '{sum += $3} END {print "Итого:", sum}' sales.txt
Счетчик
awk '/error/ {count++} END {print "Ошибок:", count}' log.txt
Конкатенация строк (просто пробел)
awk '{print $1 $2}' file.txt # JohnDoe
awk '{print $1 " " $2}' file.txt # John Doe
awk '{print $1 "-" $2}' file.txt # John-Doe
Функция length() — длина строки
awk '{print $1, length($1)}' file.txt
awk 'length($0) > 80 {print}' file.txt # Строки длиннее 80 символов
Функция substr() — подстрока
awk '{print substr($1, 1, 3)}' file.txt # Первые 3 символа
Функция tolower() и toupper()
awk '{print tolower($1)}' file.txt
awk '{print toupper($1)}' file.txt
Функция gsub() — замена всех вхождений
awk '{gsub(/old/, "new"); print}' file.txt
Функция sub() — замена первого вхождения
awk '{sub(/old/, "new"); print}' file.txt
Функция match() — поиск паттерна
awk 'match($0, /[0-9]+/) {print substr($0, RSTART, RLENGTH)}' file.txt
If-else:
Базовый if
awk '{if ($3 > 5000) print $1, "высокая зарплата"}' employees.txt
If-else
awk '{if ($4 > 5000)
print $1, "высокая"
else
print $1, "низкая"}' employees.txt
Многострочная программа
awk '{
if ($4 >= 6000)
category = "senior"
else if ($4 >= 5000)
category = "middle"
else
category = "junior"
print $1, category
}' employees.txt
Тернарный оператор:
awk '{print $1, ($4 > 5000 ? "high" : "low")}' employees.txt
For цикл:
Вывод всех полей построчно
awk '{for (i=1; i<=NF; i++) print i, $i}' file.txt
Сумма всех чисел в строке
awk '{sum=0; for(i=1; i<=NF; i++) sum+=$i; print sum}' numbers.txt
While цикл:
awk '{i=1; while(i<=NF) {print i":"$i; i++}}' file.txt
Массивы в awk ассоциативные (как хеш-таблицы) — ключом может быть любая строка.
Подсчет уникальных значений
awk '{count[$1]++} END {for (name in count) print name, count[name]}' file.txt
Суммирование по категориям
awk '{sales[$3] += $4}
END {for (dept in sales) print dept, sales[dept]}' data.txt
Подсчет IP адресов в логе:
awk '{ip_count[$1]++}
END {for (ip in ip_count) print ip, ip_count[ip]}' access.log | sort -rn -k2
Группировка по статусам HTTP:
awk '{status[$9]++}
END {for (code in status) print code, status[code]}' access.log
Нахождение дубликатов:
awk '{if (seen[$0]++) print "Дубликат:", $0}' file.txt
Удаление дубликатов (вывод уникальных строк):
awk '!seen[$0]++' file.txt
Формат access.log:
192.168.1.100 - - [24/Feb/2026:10:15:30 +0000] "GET /index.html HTTP/1.1" 200 1234
Топ-10 IP адресов по количеству запросов:
awk '{ip[$1]++} END {for (i in ip) print ip[i], i}' access.log | sort -rn | head -10
Подсчет запросов по HTTP методам:
awk '{print $6}' access.log | sort | uniq -c
Фильтрация ошибок 404:
awk '$9 == 404 {print $7}' access.log | sort | uniq -c | sort -rn
Трафик по часам:
awk '{print substr($4, 14, 2)}' access.log | sort | uniq -c
Пример CSV (sales.csv):
Date,Product,Quantity,Price
2026-02-01,Widget,10,25.50
2026-02-01,Gadget,5,120.00
2026-02-02,Widget,8,25.50
Вычисление общей выручки:
awk -F',' 'NR>1 {sum += $3 * $4} END {print "Total:", sum}' sales.csv
Сумма по продуктам:
awk -F',' 'NR>1 {total[$2] += $3 * $4}
END {for (p in total) print p, total[p]}' sales.csv
Фильтрация по дате:
awk -F',' '$1 ~ /2026-02-01/ {print $2, $3}' sales.csv
Форматированный вывод с заголовками:
awk -F',' 'BEGIN {print "Product | Total"}
NR>1 {total[$2] += $3 * $4}
END {for (p in total) printf "%-10s | $%.2f\n", p, total[p]}' sales.csv
Мониторинг использования диска:
df -h | awk 'NR>1 {if ($5+0 > 80) print $6, "занято", $5}'
Топ процессов по памяти:
ps aux | awk 'NR>1 {print $11, $4"%"}' | sort -k2 -rn | head -10
Анализ активных соединений:
netstat -an | awk '/ESTABLISHED/ {count[$5]++}
END {for (ip in count) print ip, count[ip]}' | sort -rn -k2
Проверка открытых портов:
netstat -tuln | awk 'NR>2 {print $4}' | awk -F':' '{print $NF}' | sort -n | uniq
Извлечение активных пользователей из /etc/passwd:
awk -F':' '$7 !~ /nologin|false/ {print $1, $6}' /etc/passwd
Пользователи с UID > 1000:
awk -F':' '$3 >= 1000 {print $1, $3}' /etc/passwd
Группы пользователя:
awk -F':' '/^username:/ {print $4}' /etc/passwd |
xargs -I {} awk -F':' '$3 == {} {print $1}' /etc/group
Сравнение двух файлов
awk 'NR==FNR {a[$1]; next} $1 in a' file1.txt file2.txt
Разница файлов
awk 'NR==FNR {a[$1]; next} !($1 in a)' file1.txt file2.txt
Выравнивание столбцов
awk '{printf "%-10s %8.2f\n", $1, $2}' file.txt
Таблица с заголовками
awk 'BEGIN {printf "%-10s %10s %10s\n", "Name", "Salary", "Dept"}
{printf "%-10s %10d %10s\n", $1, $4, $3}' employees.txt
Выполнение shell команды
awk '{system("echo Processing: " $1)}' file.txt
Чтение вывода команды
awk 'BEGIN {
cmd = "date"
cmd | getline result
close(cmd)
print result
}'
Подробный отчет по логам:
awk 'BEGIN {
print "=== Web Server Report ==="
print "Generated:", strftime("%Y-%m-%d %H:%M:%S")
}
{
requests++
bytes += $10
status[$9]++
if ($9 >= 400) errors++
}
END {
print "\nTotal Requests:", requests
print "Total Traffic:", bytes/1024/1024, "MB"
print "Error Rate:", (errors/requests)*100 "%"
print "\nStatus Codes:"
for (code in status)
printf " %s: %d (%.1f%%)\n", code, status[code], (status[code]/requests)*100
}' access.log
awk лучше для:
- Работы со столбцами данных
- Математических вычислений
- Сложной логики (условия, циклы)
- Создания отчетов
sed лучше для:
- Простой замены текста
- Редактирования потока
- Удаления строк
- Вставки текста
Пример задачи: Извлечь email адреса из текста
awk
awk 'match($0, /[a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z]{2,}/) {
print substr($0, RSTART, RLENGTH)
}' file.txt
sed (сложнее и менее читабельно)
sed -n 's/.*\([a-zA-Z0-9._-]\+@[a-zA-Z0-9._-]\+\.[a-zA-Z]\{2,\}\).*/\1/p' file.txt
awk преимущества:
- Быстрее для простых задач (нет накладных расходов на интерпретатор)
- Короче код для типичных операций
- Встроен в любой Linux
- Удобнее в pipe цепочках
Python преимущества:
- Больше возможностей стандартной библиотеки
- Лучше для сложной логики
- Проще отладка
- Больше документации
Сравнение кода — подсчет средней зарплаты:
awk (1 строка)
awk '{sum+=$4; count++} END {print sum/count}' employees.txt
Python (минимум 7 строк)
with open('employees.txt') as f:
total = 0
count = 0
for line in f:
salary = int(line.split()[3])
total += salary
count += 1
print(total / count)
1. Избегайте ненужных операций:
Плохо — проверка на каждой строке
awk '{if (NR > 1) print}' file.txt
Хорошо — используйте диапазон
awk 'NR > 1' file.txt
2. Используйте встроенные переменные:
Медленно
awk '{print $1, $2, $3, $4}' file.txt
Быстрее
awk '{$5=""; print}' file.txt
3. Фильтруйте рано:
Плохо — обрабатывает все строки
awk '{sum += $3} $2 == "Sales" {print}' file.txt
Хорошо — фильтрует сразу
awk '$2 == "Sales" {sum += $3; print}' file.txt
Используйте переменные:
Плохо
awk '$3 > 5000 && $4 == "IT" {print $1}' file.txt
Хорошо
awk '{
salary = $3
dept = $4
name = $1
if (salary > 5000 && dept == "IT")
print name
}' file.txt
Выносите сложные программы в файлы:
script.awk
BEGIN {
FS = ","
OFS = " | "
total = 0
}
NR > 1 {
total += $3 * $4
printf "%s | %s | %.2f\n", $1, $2, $3 * $4
}
END {
print "---"
printf "Total: $%.2f\n", total
}
Использование:
awk -f script.awk data.csv
Ошибка — CSV обрабатывается как пробелы
awk '{print $2}' data.csv
Решение — указать разделитель
awk -F',' '{print $2}' data.csv
Ошибка — заголовок участвует в вычислениях
awk '{sum += $2} END {print sum}' file.csv
Решение 1 — начать со второй строки
awk 'NR > 1 {sum += $2} END {print sum}' file.csv
Решение 2 — пропустить нечисловые
awk '{if ($2 ~ /^[0-9]+$/) sum += $2} END {print sum}' file.csv
Ошибка — возможно деление на ноль
awk '{print $1 / $2}' file.txt
Решение — проверка
awk '{if ($2 != 0) print $1 / $2; else print "N/A"}' file.txt
Ошибка — поле «New York» разбивается на два
awk -F',' '{print $3}' cities.csv
Решение — обрезка пробелов
awk -F',' '{gsub(/^ +| +$/, "", $3); print $3}' cities.csv
Как вывести последнюю колонку?
awk '{print $NF}' file.txt
Как вывести все кроме первой колонки?
awk '{$1=""; print}' file.txt
Или чище:
awk '{for(i=2;i<=NF;i++) printf "%s ", $i; print ""}' file.txt
Как подсчитать количество строк?
awk 'END {print NR}' file.txt
Или просто
wc -l file.txt
Как обработать файлы с путями содержащими пробелы?
Используйте переменную FILENAME
awk '{print FILENAME, $0}' "file with spaces.txt"
Как вывести строки между двумя паттернами?
awk '/START/,/END/' file.txt
Как удалить дубликаты сохранив порядок?
awk '!seen[$0]++' file.txt
Можно ли изменить исходный файл?
Нет, awk только читает. Для записи:
awk '{print $1, $2}' input.txt > output.txt
Как обработать JSON в awk?
Awk плохо подходит для JSON. Используйте jq:
jq '.items[] | .name' file.json
Проверка установленной версии:
awk --version
или
which awk
Основные реализации:
- gawk — GNU Awk, самая распространенная в Linux
- mawk — быстрая реализация, меньше функций
- nawk — «new awk», стандарт POSIX
- оригинальный awk — устаревший, в современных системах обычно это симлинк на gawk
Часто задаваемые вопросы
Как изменить разделитель полей в awk?
Используйте опцию -F, за которой следует нужный разделитель. Например, awk -F, ‘{print $2}’ file.csv выведет второе поле CSV-файла.
Может ли awk обрабатывать несколько файлов одновременно?
Да, awk может обрабатывать несколько файлов последовательно. Используйте awk ‘{print}’ file1.txt file2.txt для последовательной обработки файлов file1.txt и file2.txt.
Как интегрировать awk с переменными оболочки?
Вы можете передавать переменные оболочки в awk с помощью опции -v. Например, var=»value»; awk -v awkVar=»$var» ‘{print awkVar}’ file.txt выведет значение переменной оболочки var для каждой строки в file.txt.
Можно ли модифицировать файл на месте с помощью awk?
Нет, awk не поддерживает прямое редактирование на месте, как sed -i. Однако вы можете добиться этого, перенаправив вывод awk во временный файл, а затем переименовав его в исходный файл.
Можно ли использовать awk для сложной обработки текста?
Безусловно. Несмотря на то, что awk прост для выполнения базовых задач, он достаточно мощный для сложной обработки текста. Он поддерживает массивы, функции и регулярные выражения, что делает его подходящим для различных задач по работе с текстом.
Заключение
Команда awk — это универсальный инструмент командной строки для обработки текста в системах на базе Unix. Ее простые и в то же время надежные функции делают ее незаменимым инструментом для всех, кто имеет дело с текстовыми файлами — от анализа журналов до извлечения данных. Освоив awk, пользователи смогут использовать весь потенциал работы с текстом в Linux.