Как awk видит строку
Чаще всего awk нужен для одного: выделить из вывода сетевой команды конкретный столбец. Утилита читает текст построчно и делит каждую строку на поля. По умолчанию разделителем считается любая последовательность пробелов и табуляций, поэтому выровненные столбцы вывода ss или netstat разбираются без дополнительных настроек.
Поля нумеруются с единицы: $1 первое, $2 второе и так далее. Значение $0 означает строку целиком, а встроенная переменная NF хранит число полей в текущей строке, так что $NF указывает на последнее поле. Переменная NR считает прочитанные строки с начала ввода.
Программа awk состоит из пар «условие и действие в фигурных скобках». Если условия нет, действие выполняется для каждой строки. Если нет действия, по умолчанию печатается вся строка. Эти два упрощения объясняют, почему короткие команды вроде awk 'NR>1' работают без видимого print.
Столбцы в выводе, который разбирают чаще всего
Прежде чем писать номер поля, посмотрите на вывод и посчитайте столбцы вручную. Номера у разных команд разные, и в одной и той же утилите они могут сдвинуться, если какой-то столбец окажется пустым.
| Команда | Что лежит в поле |
|---|---|
| ss -tan | $1 состояние, $4 локальный адрес с портом, $5 удалённый адрес с портом |
| netstat -an на Linux | $1 протокол, $4 локальный адрес, $5 удалённый, $6 состояние |
| arp -a | в формате «имя (адрес) at MAC on интерфейс» адрес во втором поле |
| ip neigh | $1 IP-адрес, $3 интерфейс, $5 MAC-адрес, последнее поле состояние |
Первые две строки таблицы относятся к выводу, в котором есть столбцы Recv-Q и Send-Q, поэтому адреса уходят в четвёртое и пятое поля. Для остальных строк таблицы лучше проверить вывод у себя: форматы могут отличаться между системами, а ip neigh для некоторых записей добавляет дополнительные слова. Номер поля из чужой инструкции лучше не копировать вслепую, а сверять с реальной строкой.
Другой разделитель и пропуск заголовка
Если в данных разделитель не пробел, его задают ключом -F. Классический пример — файл с двоеточиями: awk -F: '{print $1}' /etc/passwd печатает имена пользователей. Для выводов с адресом и портом через двоеточие разделитель тоже можно подменить, но у IPv6 двоеточий много, и такой разбор ломается, так что порт из строки с таким адресом проще брать через $NF и дальнейшую обработку.
Заголовок таблицы — это обычная строка, и в расчётах он мешает. Условие NR>1 перед действием пропускает первую строку: awk 'NR>1 {print $5}'. У netstat -an на Linux перед таблицей две служебные строки, поэтому там пропускают их условием NR>2. Можно отбирать и по содержимому поля: awk '$1=="ESTAB" {print $5}' печатает удалённые адреса только для установленных соединений. Знак == сравнивает поле со строкой, а для поиска по шаблону используют тильду: $5 ~ /:443$/ означает «поле заканчивается на :443».
Несколько столбцов печатают через запятую: print $1, $5 выводит их через пробел. Свой разделитель вставляют строкой в кавычках: print $1 "," $5, и получается заготовка для CSV.
Типичные задачи на выводе сетевых команд
Несколько цепочек, которые решают практические вопросы. Адреса условные, формат вывода может немного отличаться на вашей системе.
- ss -tan | awk 'NR>1 {print $1}' — состояния всех сокетов, по одному на строку.
- ss -tan | awk '$1=="ESTAB" {print $5}' — удалённые адреса и порты установленных соединений.
- ip neigh | awk '{print $1, $5}' — пары «IP-адрес и MAC» из таблицы соседей, если запись содержит поле lladdr.
- ip -4 -o addr | awk '{print $2, $4}' — имя интерфейса и адрес с маской в однострочном формате ключа -o.
- ss -tan | awk 'NR>1 {print $NF}' — последнее поле каждой строки: для сокетов ss это обычно удалённый адрес с портом, но число полей зависит от того, что выводит утилита.
Результат такой цепочки обычно передают дальше: например, список удалённых адресов отдают в sort и uniq -c, чтобы увидеть, с кем соединений больше всего. Это разобрано на странице про подсчёт повторов. Если нужна только подстрока внутри поля, например адрес без порта, awk можно сочетать с cut или с функциями вроде split, но на этом этапе часто проще сначала отфильтровать нужное, а потом форматировать.
Ошибки, из-за которых awk молчит или врёт
Первая ошибка связана с кавычками. Программу awk пишут в одинарных кавычках, иначе оболочка сама подставит $1 как свой параметр, и вместо столбца получится пустая строка или целиком вся строка. Если команда запускается из обычного терминала bash или zsh, одинарные кавычки решают вопрос.
Вторая — сдвиг столбцов. Когда в одной из строк значение отсутствует, остальные поля сдвигаются влево, и $5 уже не тот, что в соседних строках. Проверьте на нескольких строках и при необходимости добавьте условие по NF.
Третья — лишние пробелы в данных. Если поля разделены одиночным пробелом, а внутри значения тоже есть пробел, awk посчитает это новым полем. Тогда нужен точный -F.
Четвёртая — различия реализаций. В Linux обычно стоит gawk или mawk, в macOS своя версия awk. Простые вещи вроде $1, $NF, -F и NR работают одинаково, а расширенные функции лучше проверять в справке именно вашей версии.
Счётчики и суммы без отдельных утилит
Кроме выбора столбцов, awk умеет считать. Блок END выполняется после последней строки, а значения можно копить в переменных и словарях. Это позволяет не строить цепочку из нескольких команд, если задача небольшая.
Сумма чисел из столбца: awk '{s+=$2} END {print s}'. Число строк, в которых первое поле равно нужному значению: awk '$1=="ESTAB" {n++} END {print n}'. Если переменная n ни разу не увеличилась, awk напечатает пустую строку, а не ноль, поэтому для вывода пишут print n+0.
Подсчёт по группам делает словарь: ss -tan | awk 'NR>1 {c[$1]++} END {for (k in c) print k, c[k]}' выведет каждое состояние и число сокетов в нём. Порядок строк при переборе словаря не определён, так что при необходимости результат отдают в sort.
Такие однострочники удобны для быстрой проверки, но длинные программы лучше хранить в файле и запускать ключом -f. Правила чтения при этом остаются теми же: условие, действие, поля с номерами.