Команда awk: вывод полей, разделитель -F и условные шаблоны
Команда awk — это инструмент Linux, который читает текстовый файл строка за строкой, разбивает каждую строку на поля по пробелам или указанному вами разделителю и выбирает только поля строк, соответствующих условию, чтобы вывести их или выполнить вычисления. На сервере AlmaLinux 9 мы подсчитали запросы по IP-адресам и количество по кодам состояния в примере журнала доступа веб-сервера одной строкой, соединённой конвейером с sort, и оказалось, что все три ответа 404 из двенадцати строк были запросами к wp-login.php и .env с одного IP.
Приведённый ниже вывод получен под учётной записью root в рабочей папке на сервере AlmaLinux 9.8. Журнал доступа, список учётных записей, записи о продажах и файл с баллами — это примеры, созданные для теста, а IP-адреса и имена учётных записей в них тоже являются примерами.
1️⃣ Основы использования команды awk
awk разбивает прочитанную строку по пробелам и нумерует поля с начала как $1, $2, $3. Мы проверили это на файле scores.txt, где имя, результат и баллы разделены пробелами.
cat scores.txtalice pass 82
bob fail 47
carol pass 91
dave pass 68
erin fail 55Фигурные скобки внутри одинарных кавычек содержат действие для каждой строки, а если после print перечислить номера полей через запятую, будут выведены только эти поля. При выводе первого и третьего полей остаются только имя и баллы.
awk '{print $1, $3}' scores.txtalice 82
bob 47
carol 91
dave 68
erin 55Если убрать запятую между полями и написать $1 $3, два значения выводятся слитно, без пробела. Запятая в print вставляет разделитель вывода (по умолчанию один пробел), а значения, написанные рядом без запятой, склеиваются в одну строку.
awk '{print $1 $3}' scores.txtalice82
bob47
carol91
dave68
erin55NR — это номер прочитанной к этому моменту строки, NF — число полей в ней. $NF означает последнее поле, поэтому последний столбец можно выбрать, даже если число полей в строках разное.
awk '{print NR, NF, $NF}' scores.txt1 3 82
2 3 47
3 3 91
4 3 68
5 3 55Журнал доступа веб-сервера тоже разделён пробелами, поэтому поля выбираются так же. Номера полей первой строки тестового журнала приведены ниже.
| Поле | Значение в первой строке | Назначение |
|---|---|---|
| $1 | 192.0.2.10 | IP клиента |
| $4 | [29/Oct/2026:00:01:12 | Дата и время запроса |
| $6 | "GET | Метод запроса (с двойной кавычкой впереди) |
| $7 | /index.html | URL запроса |
| $9 | 200 | Код статуса |
| $10 | 5120 | Отправленные байты |
| $11 | "-" | Предыдущая страница (Referer) |
| $12~$15 | "Mozilla/5.0 (X11; Linux x86_64)" | User agent (делится на каждом пробеле) |
Мы вывели $1, $7 и $9, то есть IP клиента, URL запроса и код состояния.
awk '{print $1, $7, $9}' access.log192.0.2.10 /index.html 200
198.51.100.7 /about.html 200
192.0.2.10 /images/logo.png 200
203.0.113.25 /wp-login.php 404
203.0.113.25 /wp-login.php 404
192.0.2.10 /contact.html 200
198.51.100.7 /old-page.html 301
203.0.113.25 /.env 404
192.0.2.44 /index.html 200
198.51.100.7 /api/search?q=awk 500
192.0.2.44 /images/logo.png 304
192.0.2.10 /index.html 200Столбец с пробелами в значении, например user agent, разбивается на несколько полей. NF во всех трёх первых строках равно 15, а $NF — последний фрагмент user agent.
awk '{print NF, $NF}' access.log | head -315 x86_64)"
15 x86_64)"
15 x86_64)"2️⃣ Задание разделителя через awk -F
Для файла, столбцы которого разделены не пробелом, укажите этот символ после -F. При выводе $1 без -F из списка учётных записей users.txt, составленного по образцу /etc/passwd, большинство строк вышло целиком.
awk '{print $1}' users.txtroot:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
nobody:x:65534:65534:Kernel
user:x:1000:1000:Example
deploy:x:1001:1001:Deploy
backup:x:1002:1002::/home/backup:/sbin/nologinРазделитель по умолчанию — пробел, поэтому строка, соединённая только двоеточиями, содержит одно поле. Только строки nobody, user и deploy с пробелом в столбце описания обрезаются на этом пробеле.
С -F: двоеточие становится разделителем, и имя учётной записи ($1) и оболочка входа ($7) разделяются.
awk -F: '{print $1, $7}' users.txtroot /bin/bash
bin /sbin/nologin
daemon /sbin/nologin
nobody /sbin/nologin
user /bin/bash
deploy /bin/bash
backup /sbin/nologinCSV-файлы с запятыми разбиваются через -F,. При выводе товара и количества из записей о продажах sales.csv заголовок в первой строке (item qty) разбивается так же и выводится вместе с ними.
awk -F, '{print $2, $3}' sales.csvitem qty
keyboard 2
mouse 5
monitor 1
keyboard 1
cable 10
mouse 2
monitor 2-F, не подходит для CSV с запятыми внутри столбцов в двойных кавычках. В quoted.csv с запятыми в столбце товара поля разбиваются и на запятых внутри кавычек, и во втором поле остаётся только начало названия товара.
awk -F, '{print $2}' quoted.csvitem
"cable
keyboardДля таких файлов официальное руководство GNU Awk описывает переменную FPAT. Если вместо разделителя записать форму одного поля регулярным выражением, столбец в кавычках станет одним полем.
awk -v FPAT='([^,]*)|("[^"]*")' '{print $2}' quoted.csvitem
"cable, usb"
keyboardЧтобы использовать несколько разделителей, запишите их регулярным выражением в квадратных скобках. Если разделители — двоеточие и косая черта, $NF становится последним именем в пути оболочки входа (bash, nologin).
awk -F'[:/]' '{print $1, $NF}' users.txtroot bash
bin nologin
daemon nologin
nobody nologin
user bash
deploy bash
backup nologin3️⃣ Условные шаблоны команды awk
Даже при выборе полей выводятся все строки, поэтому, чтобы оставить только нужные, поставьте условие (шаблон) перед фигурными скобками. Строка между косыми чертами выбирает только содержащие её строки, а если действие опущено, выводится вся строка.
awk '/wp-login/' access.log203.0.113.25 - - [29/Oct/2026:00:04:51 +0000] "POST /wp-login.php HTTP/1.1" 404 196 "-" "Mozilla/5.0 (X11; Linux x86_64)"
203.0.113.25 - - [29/Oct/2026:00:04:52 +0000] "POST /wp-login.php HTTP/1.1" 404 196 "-" "Mozilla/5.0 (X11; Linux x86_64)"Выбранные строки те же, что и у команды grep, а awk сразу выбирает из них поля и выводит их. Если передать по конвейеру в awk те же две строки, выбранные через grep, останутся только IP и код состояния.
grep wp-login access.log | awk '{print $1, $9}'203.0.113.25 404
203.0.113.25 404Значения полей сравниваются через ==, !=, >, >=, <, <=. Мы выбрали только строки с кодом состояния ($9) 404 и вывели IP и URL запроса.
awk '$9 == 404 {print $1, $7}' access.log203.0.113.25 /wp-login.php
203.0.113.25 /wp-login.php
203.0.113.25 /.envПри сравнении со строкой заключите значение в двойные кавычки. Мы выбрали только имена, у которых второе поле равно pass.
awk '$2 == "pass" {print $1}' scores.txtalice
carol
daveЧисловое сравнение нужно для выбора по диапазону, например по номерам учётных записей (UID). При выборе записей с UID от 1000 и выше вместе с обычными записями попадает и nobody с UID 65534.
awk -F: '$3 >= 1000 {print $1, $3}' users.txtnobody 65534
user 1000
deploy 1001
backup 1002Два условия объединяются через &&. Если добавить условие меньше 65534, nobody исчезает, и остаются только три обычные учётные записи и их домашние папки.
awk -F: '$3 >= 1000 && $3 < 65534 {print $1, $6}' users.txtuser /home/user
deploy /home/deploy
backup /home/backup[~] проверяет, соответствует ли поле регулярному выражению, а [!~] — что не соответствует. Если выбрать записи, у которых оболочка входа ($7) заканчивается на bash, и записи без nologin, получаются те же три записи.
awk -F: '$7 ~ /bash$/ {print $1}' users.txtroot
user
deployawk -F: '$7 !~ /nologin/ {print $1, $7}' users.txtroot /bin/bash
user /bin/bash
deploy /bin/bashУсловие NR выбирает по номеру строки. NR > 1 убирает строку заголовка CSV, и остаются только записи о продажах.
awk -F, 'NR > 1 {print $2, $3}' sales.csvkeyboard 2
mouse 5
monitor 1
keyboard 1
cable 10
mouse 2
monitor 2Вывод других команд тоже можно передать по конвейеру и разбить так же. При выборе размера файла ($5) и имени ($9) из вывода ls -l первая строка вышла пустой, потому что в первой строке ls -l, [total 24], нет пятого и девятого полей.
ls -l | awk '{print $5, $9}'
1567 access.log
79 quoted.csv
207 sales.csv
85 scores-copy.txt
85 scores.txt
315 users.txtС NR > 1 первая строка исчезает, и остаются только размеры и имена файлов.
ls -l | awk 'NR > 1 {print $5, $9}'1567 access.log
79 quoted.csv
207 sales.csv
85 scores-copy.txt
85 scores.txt
315 users.txt4️⃣ awk BEGIN, END, сумма и среднее
Блок BEGIN выполняется один раз перед чтением первой строки, а блок END — один раз после обработки последней. Для суммы прибавляйте значение к переменной в каждой строке и выводите её в END. Схема ниже показывает порядок, который awk проходит для каждой строки при суммировании сумм из записей о продажах.
$ awk -F, 'NR > 1 {t += $3 * $4} END {printf "total %.2f\n", t}' sales.csvСумма всех отправленных байтов ($10) в журнале доступа составила 41298 байт. Впервые используемая переменная начинается с пустого значения (как число — 0), поэтому задавать 0 отдельно не нужно.
awk '{sum += $10} END {print sum}' access.log41298Если выводить сумму не в END, а в действии для каждой строки, при чтении каждой строки появляется накопленная сумма. Если при каждом прибавлении произведения количества на цену выводить номер строки и t, получится семь строк без заголовка, а 886.3 в последней строке — общая сумма.
awk -F, 'NR > 1 {t += $3 * $4; print NR, t}' sales.csv2 90
3 189.5
4 378.5
5 423.5
6 468.5
7 508.3
8 886.3Среднее вычисляется в END делением суммы на число строк. Сумма баллов в пяти строках составила 343, среднее — 68.6.
awk '{total += $3; n++} END {print total, n, total / n}' scores.txt343 5 68.6BEGIN нужен, чтобы один раз вывести строку заголовка над результатами. Над товарами и суммами (количество × цена за единицу) строка item total появляется только один раз.
awk -F, 'BEGIN {print "item", "total"} NR > 1 {print $2, $3 * $4}' sales.csvitem total
keyboard 90
mouse 99.5
monitor 189
keyboard 45
cable 45
mouse 39.8
monitor 378Разделитель вывода меняется переменной OFS в BEGIN. Если задать OFS запятую, на месте запятых в print ставится запятая вместо пробела, и список учётных записей выводится в формате CSV.
awk 'BEGIN {FS = ":"; OFS = ","} {print $1, $3, $7}' users.txtroot,0,/bin/bash
bin,1,/sbin/nologin
daemon,2,/sbin/nologin
nobody,65534,/sbin/nologin
user,1000,/bin/bash
deploy,1001,/bin/bash
backup,1002,/sbin/nologinДля выравнивания столбцов используйте printf. %-10s — строка с выравниванием влево на 10 позиций, %3d — целое число на 3 позиции, %8.2f — число на 8 позиций с двумя знаками после запятой.
awk -F, 'NR > 1 {printf "%-10s %8.2f\n", $2, $3, $3 * $4}' sales.csvkeyboard 2 90.00
mouse 5 99.50
monitor 1 189.00
keyboard 1 45.00
cable 10 45.00
mouse 2 39.80
monitor 2 378.00В отличие от print, printf не переводит строку, поэтому в конце формата нужно написать [\n]. Без [\n] названия товаров сливаются в одну строку.
awk -F, 'NR > 1 {printf "%s ", $2}' sales.csvkeyboard mouse monitor keyboard cable mouse monitor5️⃣ Анализ журналов и опции команды awk
🔲 Анализ журналов
Прибавление к одной переменной даёт только одну сумму, поэтому для подсчёта по IP или коду состояния собирайте значения в массив. n[$1]++ прибавляет 1 к элементу массива с ключом IP, а for (ip in n) в END достаёт собранные элементы по одному.
awk '{n[$1]++} END {for (ip in n) print n[ip], ip}' access.log | sort -rn4 192.0.2.10
3 203.0.113.25
3 198.51.100.7
2 192.0.2.44Порядок, в котором for (ip in n) достаёт элементы, не определён (по руководству GNU Awk), поэтому мы отсортировали их по числу запросов через sort -rn. Больше всего запросов у 192.0.2.10 — 4.
Количество по кодам состояния считается так же. Было 3 ответа 404 и 1 ответ 500.
awk '{n[$9]++} END {for (s in n) print s, n[s]}' access.log | sort200 6
301 1
304 1
404 3
500 1Если извлечь только коды состояния и передать их в sort и uniq -c, получится то же количество.
awk '{print $9}' access.log | sort | uniq -c 6 200
1 301
1 304
3 404
1 500Чтобы увидеть только ответы с ошибками, задайте условие на код состояния. Строки от 400 и выше — это три запроса, искавшие wp-login.php и .env, и одна ошибка 500.
awk '$9 >= 400 {print $9, $1, $7}' access.log404 203.0.113.25 /wp-login.php
404 203.0.113.25 /wp-login.php
404 203.0.113.25 /.env
500 198.51.100.7 /api/search?q=awkСумма отправленных байтов по IP тоже считается в массиве. Больше всего получил 192.0.2.10 — 31340 байт.
awk '{b[$1] += $10} END {for (ip in b) print b[ip], ip}' access.log | sort -rn31340 192.0.2.10
5120 192.0.2.44
4250 198.51.100.7
588 203.0.113.25Поле времени ($4) можно сравнивать как строку. В строках с одинаковой датой и форматом порядок строк совпадает с порядком времени, поэтому мы выбрали только четыре запроса с 00:05 до 00:10.
awk '$4 >= "[29/Oct/2026:00:05" && $4 < "[29/Oct/2026:00:10" {print $4, $7}' access.log[29/Oct/2026:00:05:30 /contact.html
[29/Oct/2026:00:07:02 /old-page.html
[29/Oct/2026:00:07:15 /.env
[29/Oct/2026:00:09:48 /index.html🔲 Опции команды awk
📌 Основные опции: результаты из этой статьи
| Опция | Назначение | Результат в этой статье |
|---|---|---|
| -F fs | Задаёт разделитель полей ввода | -F: разделяет имя учётной записи ($1) и оболочку входа ($7) в users.txt, -F, выводит товар и количество из sales.csv вместе с заголовком (item qty) |
| -v var=val | Задаёт значение переменной перед запуском программы | Передача переменной оболочки min через -v min=$min выводит шесть строк с отправленными байтами от 1000, с -v FPAT=… столбец в кавычках в quoted.csv становится одним полем |
| -i inplace | Сохраняет вывод в исходный файл вместо экрана | После gawk -i inplace на экране ничего не появляется, а копия scores.txt сокращается до двух столбцов, имени и баллов, с -v inplace::suffix=.bak прежнее содержимое остаётся в файле .bak |
| --version | Выводит сведения о версии | Первая строка [awk --version] показывает версию GNU Awk 5 |
📎 Другие опции: по официальному руководству
| Опция | Назначение |
|---|---|
| -f program-file | Читает программу AWK из файла вместо первого аргумента командной строки, -f можно указывать несколько раз |
| -e program-text | Использует текст в командной строке как исходный код программы AWK, можно сочетать с функциями библиотек, загруженными через -f или --include |
| -E file | Похожа на -f, но обрабатывается последней и блокирует присваивание переменных в командной строке, для скриптов #! |
| --traditional | Работает в режиме совместимости, не распознаёт расширения GNU |
| --posix | Включает режим совместимости с дополнительными ограничениями, например не распознаёт func, синоним function |
| --lint | Предупреждает о сомнительных или плохо переносимых на другие реализации AWK конструкциях, с --lint=fatal предупреждения становятся фатальными ошибками |
| --dump-variables | Записывает в файл отсортированный список глобальных переменных с типами и итоговыми значениями, если файл не указан — в awkvars.out |
🔲 Симулятор команды awk
В симуляторе ниже вы можете сами вводить команды awk для тех же тестовых файлов.
🔢 FAQ & рекомендуемые материалы
Сортировка
Команда sort в Linux: сортировка файлов
Команда sort сортирует содержимое файла по алфавиту или по числу. Используйте её следом, чтобы увидеть итоги awk от большего к меньшему.
Удаление дубликатов
Команда uniq в Linux
Команда uniq сводит идущие подряд одинаковые строки в одну и с -c считает повторы.
Просмотр файлов
Команды head и tail в Linux
Команды head и tail показывают только первые или последние строки файла. Их часто используют для проверки журнала доступа сервера.
ℹ️ О партнёрских ссылках
Материалы этого сайта содержат партнёрские ссылки. Если посетитель покупает товар или услугу по такой ссылке, сайт получает комиссию от продавца. При этом сумма, которую платит покупатель (при акционных скидках сумма снижается ↓), не увеличивается. Указанные цены, скидки и наличие актуальны на момент написания и могут отличаться, поэтому перед покупкой уточняйте их у продавца. Товары выбираются и оцениваются по нашим собственным критериям, а комиссия не влияет ни на порядок, ни на содержание обзоров.