AWK назван в честь фамилии его авторов: Альфред Ахо, Питер Вайнбергером и Брайан Керниган. AWK очень полезный язык сценариев для обработки текста. Этот язык выполняется в интерпретаторе. Это позволяет пользователю обрабатывать некоторые входные, определять переменные, использовать логические операторы, строки и числовые функции, извлечения данных и создания отформатированных отчетов. Синтаксис AWK очень близок с языку C и является прямым предшественником Perl. Все сценарии AWK могут быть преобразованы в сценарии Perl с использованием утилиты A2P.

Для чего нужен awk?

awk — это утилита/язык для извлечения данных. Именно awk являлся источником вдохновения для Larry Wall, когда он создавал Perl. Для выполнения различных практических задач по обработке текста awk часто используется совместно с sed. В зависимости от поставленной задачи вы можете использовать либо awk, либо Perl, хотя это в большей степени зависит от личных предпочтений. Как и sed, awk читает за один раз одну строку, выполняет определенные действия в зависимости от заданных опций, и выводит результат. Одним из самых простых и популярных способов использования awk является выбор столбца из текстового файла или из вывода другой команды. Когда я устанавливал Debian на свою вторую рабочую станцию, я использовал awk для того, чтобы получить список установленных на первой машине, и скормить его aptitude. Я делал это с помощью команды вида:

$ dpkg -l | awk ‘ {print $2} ‘ > installed

В настоящее время большинство менеджеров пакетов предоставляют такую возможность, например это можно сделать с помощью команды rpm’s -qa, но вывод содержит больше информации, чем мне нужно. Я вижу, что второй столбец вывода dpkg -l содержит названия установленных пакетов, поэтому я использовал вышеприведенную команду, чтобы извлечь только второй столбец.

В защиту awk

В этой серии статей я собираюсь сделать из читателя искусного программиста на awk. Я согласен, что у awk не самое приятное и модное имя, а GNU-версия awk, названная gawk, звучит откровенно странно. Незнакомые с этим языком программисты, услышав его название, возможно, представят себе мешанину древнего и устаревшего кода, способного довести до умопомрачения даже самого знающего специалиста по UNIX (заставив его восклицать «kill -9!» и беспрестанно бегать за кофе).

Да, у awk отнюдь не замечательное имя. Но это замечательный язык. Awk создан для обработки текста и создания отчетов, но у него много хорошо проработанных функций, дающих возможность серьезного программирования. При этом, в отличие от некоторых других языков, синтаксис awk привычен и заимствует лучшее из таких языков, как C, python и bash (хотя формально awk был создан до python и bash). Awk — один из тех языков, которые, будучи один раз выучены, становятся ключевой частью стратегического арсенала программиста.

Базовые концепции

Как уже говорилось, действия, выполняемые awk, заключаются в фигурные скобки, а вся команда — в одинарные кавычки: awk ‘condition { action }‘. В нашем примере условий нет, но если мы захотим, например, выбрать только установленные пакеты, относящиеся к vim, (да, есть grep, но ведь это пример, кроме того, зачем использовать две утилиты, если можно использовать одну), мы могли мы набрать:

$ dpkg -l | awk ‘ /’vim’/ {print $2} ‘

Эта команда выведет все установленные пакеты, содержащие «vim» в названиях. Одна из причин, по которой рекомендуется использовать awk — он быстр. Если заменить «vim» на «lib», в моей системе получится список из более чем 1300 пакетов. Встречаются ситуации, где данных намного больше, и в этих случаях awk показывает все свои преимущества. В любом случае, давайте рассмотрим примеры, которые помогут понять многие аспекты использования программы. Но перед этим будет полезно узнать, что существует несколько диалектов и реализаций awk. Примеры, приведенные в данной статье, относятся к GNU awk (так к реализации, так и к диалекту). Из-за различий в интерпретации кавычек, мы можем использовать bash, ksh или sh, но не можем использовать (t)csh.

Предпосылки

Интерпретатор AWK является стандартным инструментом, найденным на каждом дистрибутиве Linux. Пакет gawk содержит версию AWK с открытым исходным кодом, и в зависимости от дистрибутива Linux он может быть установлен из исходного файла или с помощью пакетов gawk или mawk, включенных в конкретный дистрибутив Linux.

Как работает awk?

На самом деле awk – это изначально язык программирования, предназначенный для обработки текста/данных. Поскольку, как уже отмечалось, в Linux-системах основной средой для взаимодействия между пользователем и машиной является текст, то обработка достаточно больших его объёмов вручную способна была парализовать на некоторое время процесс выполнения основной работы. Требовался инструмент для обеспечения автоматической обработки данных и позволяющий использовать эту возможность «на лету», т. е. прямо при работе в командной оболочке. Лучшим средством для достижения этой цели является использование специализированного языка программирования и регулярных выражений, которое реализовано в виде одноимённой утилиты — команды awk.

Справедливо заметить, что awk – это прежде всего Си-подобный язык программирования, но для удобства понимания, под awk принято понимать утилиту или команду. Разработчиками языка AWK являются Alfred V. Aho, Peter J. Weinberger и Brian W. Kernighan, по сокращённым инициалам которых язык и получил своё название. Создан язык в 1977 году. Кстати, на основе AWK когда-то был создан язык Perl, который и по сей день является одним из самых мощных языков для высокопроизводительной обработки данных.

В качестве исходных данных awk принимает на вход строку и после её обработки в зависимости от конкретных опций выдаёт результат. Исходные данные могут поступать из файла или из вывода другой команды/программы. Самым распространённым случаем использования awk является выборка определённых столбцов из результата вывода других команд, например:

$ ll | awk ‘{print $9}’

В результате вывод будет примерно таким:

Следует напомнить, что по-умолчанию вывод команды ll выглядит следующим образом:

Как видно, команда awk помогла вывести только отдельный столбец из общего вывода ll – с именами каталогов и файлов.

Конечно, для решения подобных задач существует утилита grep, но awk гораздо быстрее и производительнее для обработки больших и сложных массивов данных.

Установка

Войдите на сервер через SSH с правами суперпользователя

ssh root@IP_Address

Для того, чтобы установить утилиту командной строки  AWK на CentOS/Fedora или на любую другую на основе RPM распределения Linux, выполните следующую команду:

yum install gawk

В Ubuntu/Debian, вам нужно вызвать эту команду, чтобы установить Gawk:

apt-get install gawk

Примеры команды AWK

Простые команды awk могут быть легко запущены из командной строки, а для более сложных задач должны быть записаны в виде сценариев awk в файл. Ниже перечислены некоторые полезные примеры команд awk и исполняемых скриптов.

Вы можете использовать команду AWK для печати только определенных столбцов из поля ввода. Например, с помощью команды приведенной ниже вы можете узнать список IP-адресов, которые подключены к серверу:

netstat -anp|grep tcp|awk ‘{print $5}’| cut -d : -f1 | sort | uniq -c | sort -n

Это очень полезно, если вы расследуете, находиться ли ваш сервер под атакой DoS или DDoS.

В следующем примере мы используем AWK для поиска конкретного шаблона в определенных столбцах и делаем какое-то действие, на основе результата:

exim -bpr | grep frozen | awk {‘print $3’} | xargs exim -Mrm

Выше команда удалит все замороженные сообщения электронной почты из почтовой очереди Exim.

AWK часто используется для выполнения полезной и практической обработки и манипуляции текста. Например, мы можем использовать AWK для удаления дубликатов в текстовом файле без сортировки:

awk ‘!x[$0]++’ file-with-duplicates > new-file-without-duplicates

Следующая команда напечатает пять случайных чисел от 0 до 999:

awk ‘BEGIN { for (i = 1; i <= 5; i++) print int(1000 * rand()) }’

Используйте следующую команду, чтобы подсчитать количество строк в файле с именем «sample_file»:

awk ‘END { print NR }’ sample_file

Следующая команда выведет все строки в файле «sample_file», которые содержат строки, начинающиеся с ‘ A ‘ или ‘a’, за которыми следует ‘ re’:

awk ‘/[Aa]re/{print}’ /opt/sample_file

Вы можете использовать команду AWK для более сложных операций. Если ваш веб-сайт работает довольно медленно, вы можете использовать следующую команду, чтобы проверить, есть ли какая-то проблема с диском I/O (и/или сети, в некоторых редких случаях):

tac /proc/stat | awk ‘/^btime/ {up=systime()-$2;print «up » up/86400 «d»}; /^cpu / {print «user » $2/up «%, nice » $3/up «%, sys » $4/up «%, idle » $5/up «%, iowait » $6/up «%, steal » $9/up «%niowait/used » $6 / ($2+$3+$4) «, steal/used » $9 / ($2+$3+$4) }’

IOWAIT означает, как долго процессы блокируются занятые вводом/выводом, в основном дискового хранения или, возможно, сети. STEAL означает, как долго процессы блокируются удачей CPU Time slice на сервере. Выше iowait на время процессора пользователя (=USER + NICE + SYSTEM) показывает занят ввода / вывода, выше украсть просматривается показывает занят CPU.

Следующий сценарий использует простую команду awk, которая выполняет поиск во входном файле ‘/etc/passwd ‘ и предоставляет вывод с именем пользователя, за которым следует дата и время последнего входа:

vi login-check#!/bin/bash for user in `awk -F: ‘{print $1}’ /etc/passwd` do echo -n «$user: » finger $user | grep Last if [ $? != 0 ]; then echo fi done

Сделайте скрипт исполняемым:

chmod 755 login-check

Выполните скрипт:

./login-check

Вы должны состоянии увидеть учетные записи пользователей, доступных на сервере, а затем по дате и времени последнего входа в систему каждого пользователя.

Первый шаг в awk

Давайте начнем и попробуем поэкспериментировать с awk, чтобы увидеть, как он работает. В командной строке введем следующую команду:

$ awk ‘{ print }’ /etc/passwd

В результате должно быть показано содержимое файла /etc/passwd. Теперь — объяснение того, что делал awk. Вызывая awk, мы указали /etc/passwd в качестве входного файла. Когда мы запустили awk, он обработал команду print для каждой строки в /etc/passwd по порядку. Весь вывод отправлен в stdout, и мы получили результат, идентичный результату команды cat /etc/passwd. Теперь объясним блок { print }. В awk фигурные скобки используются для группирования блоков текста, как в C. В нашем блоке текста есть лишь одна команда print. В awk команда print без дополнительных параметров печатает все содержимое текущей строки.

Вот еще один пример программы на awk, которая делает то же самое:

$ awk ‘{ print $0 }’ /etc/passwd

В awk переменная $0 представляет всю текущую строку, поэтому print и print $0 делают в точности одно и то же. Если угодно, можно создать программу на awk, которая будет выводить данные, совершенно не связанные с входными данными. Вот пример:

$ awk ‘{ print «» }’ /etc/passwd

При передаче строки «» команде print она всегда печатает пустую строку. Если протестировать этот скрипт, обнаружится, что awk выводит одну пустую строку на каждую строку в файле /etc/passwd. Это опять-таки происходит потому, что awk исполняет скрипт для каждой строки во входном файле. Вот еще один пример:

$ awk ‘{ print «hiya» }’ /etc/passwd

Если запустить этот скрипт, он заполнит экран словами «ура». 🙂

Множественные поля

Awk хорошо подходит для обработки текста, разбитого на множество логических полей, и дает возможность без усилий обращаться к каждому отдельному полю из awk-скрипта. Следующий скрипт распечатает список всех учетных записей в системе:

$ awk -F»:» ‘{ print $1 }’ /etc/passwd

В вызове awk в вышеприведенном примере параметр –F задает «:» в качестве разделителя полей. Обрабатывая команду print $1, awk выводит первое поле, встреченное в каждой строке входного файла. Вот еще один пример:

$ awk -F»:» ‘{ print $1 $3 }’ /etc/passwd

Вот фрагмент из вывода на экран этого скрипта:

halt7 operator11 root0 shutdown6 sync5 bin1 ….etc.

Как видим, awk выводит первое и третье поля файла /etc/passwd, которые представляют собой соответственно поля имени пользователя и uid. При этом, хотя скрипт и работает, он не совершенен — нет пробелов между двумя выходными полями! Те, кто привык программировать в bash или python, возможно ожидали, что команда print $1 $3 вставит пробел между этими двумя полями. Однако когда в программе на awk две строки оказываются рядом друг с другом, awk сцепляет их без добавления между ними пробела. Следующая команда вставит пробел между полями:

$ awk -F»:» ‘{ print $1 » » $3 }’ /etc/passwd

Когда print вызывается таким способом, он последовательно соединяет $1, » » и $3, создавая удобочитаемый вывод на экране. Конечно, мы можем также вставить метки полей, если нужно:

$ awk -F»:» ‘{ print «username: » $1 «ttuid:» $3″ }’ /etc/passwd

В результате получаем такой вывод:

username: halt uid:7 username: operator uid:11 username: root uid:0 username: shutdown uid:6 username: sync uid:5 username: bin uid:1 ….etc.

Использование awk в Linux

Простейшая и часто востребованная задача — выборка полей из стандартного вывода. Вы не найдете более подходящего инструмента для решения этой задачи, чем awk. По умолчанию awk разделяет поля пробелами. Если вы хотите напечатать первое поле, вам нужно просто использовать функцию print и передать ей параметр $1, если функция одна, то скобки можно опустить:

echo ‘one two three four’ | awk ‘{print $1}’

Да, использование фигурных скобок немного непривычно, но это только в первое время. Вы уже догадались как напечатать второе, третье, четвертое, или другие поля? Правильно это $2, $3, $4 соответственно.

echo ‘one two three four’ | awk ‘{print $3}’

Иногда необходимо представить данные в определенном формате, например, выбрать несколько слов. AWK легко справляется с группировкой нескольких полей и даже позволяет включать статические данные:

echo ‘one two three four’ | awk ‘{print $3,$1}’

echo ‘one two three four’ | awk ‘{print «foo:»,$3,»| bar:»,$1}’

Если поля разделены не пробелами, а другим разделителем, просто укажите в параметре -F нужный разделитель в кавычках, например «:» :

echo ‘one mississippi:two mississippi:three mississippi:four mississippi’ | awk -F»:» ‘{print $4}’

Но разделитель не обязательно заключать в кавычки. Следующий вывод аналогичен предыдущему:

echo ‘one mississippi:two mississippi:three mississippi:four mississippi’ | awk -F: ‘{print $4}’

Иногда нужно обработать данные с неизвестным количеством полей. Если вам нужно выбрать последнее поле можно воспользоваться переменной $NF. Вот так вы можете вывести последнее поле:

echo ‘one two three four’ | awk ‘{print $NF}’

Также вы можете использовать переменную $NF для получения предпоследнего поля:

echo ‘one two three four’ | awk ‘{print $(NF-1)}’

Или поля с середины:

echo ‘one two three four’ | awk ‘{print $((NF/2)+1)}’

echo ‘one two three four five’ | awk ‘{print $((NF/2)+1)}’

Все это можно сделать с помощью таких утилит как sed, cut и grep но это будет намного сложнее.

Как я рассказывал выше, awk обрабатывает одну строку за раз, вот этому подтверждение:

echo -e ‘one 1n two 2’ | awk ‘{print $1}’

А вот пример фильтрации с помощью условия, выведем только строку, в которой содержится текст one:

echo -e ‘one 1n two 2’ | awk ‘/one/ {print $1}’

А вот пример использования операций с переменными:

echo -e ‘one 1n two 2’ | awk ‘{sum+=$2} END {print sum}’

Это означает что мы должны выполнять следующий блок кода для каждой строки. Это можно использовать, например, для подсчета количества переданных данных по запросам из журнала веб-сервера.

Представьте себе, у нас есть журнал доступа, который выглядит так:

Мы можем подсчитать, что количество переданных байт, это десятое поле. Дальше идёт User-Agent пользователя и он нам не интересен:

cat /var/log/apache2/access.log | awk ‘{print $10}’

Вот так можно подсчитать количество байт:

< requests.log awk ‘{totalBytes+=$NF} END {print totalBytes}’

Это только несколько примеров показывающих использование awk в Linux , освоив awk один раз в получите очень мощный и полезный инструмент на всю жизнь.

Синтаксис команды awk

Сначала надо понять как работает утилита. Она читает документ по одной строке за раз, выполняет указанные вами действия и выводит результат на стандартный вывод. Одна из самых частых задач, для которых используется awk — это выборка одной из колонок. Все параметры awk находятся в кавычках, а действие, которое надо выполнить — в фигурных скобках. Вот основной её синтаксис:

$ awkопции’условие{действие}’

$ awkопции’условие{действие} условие {действие}’

С помощью действия можно выполнять преобразования с обрабатываемой строкой. Об этом мы поговорим позже, а сейчас давайте рассмотрим опции утилиты:

  • -F, —field-separator — разделитель полей, используется для разбиения текста на колонки;
  • -f, —file — прочитать данные не из стандартного вывода, а из файла;
  • -v, —assign — присвоить значение переменной, например foo=bar;
  • -b, —characters-as-bytes — считать все символы однобайтовыми;
  • -d, —dump-variables — вывести значения всех переменных awk по умолчанию;
  • -D, —debug — режим отладки, позволяет вводить команды интерактивно с клавиатуры;
  • -e, —source — выполнить указанный код на языке awk;
  • -o, —pretty-print — вывести результат работы программы в файл;
  • -V, —version — вывести версию утилиты.

Это далеко не все опции awk, однако их вам будет достаточно на первое время. Теперь перечислим несколько функций-действий, которые вы можете использовать:

  • print(строка) — вывод чего либо в стандартный поток вывода;
  • printf(строка) — форматированный вывод в стандартный поток вывода;
  • system(команда) — выполняет команду в системе;
  • length(строка) — возвращает длину строки;
  • substr(строка, старт, количество) — обрезает строку и возвращает результат;
  • tolower(строка) — переводит строку в нижний регистр;
  • toupper(строка) — переводить строку в верхний регистр.

Функций намного больше, но чтобы не загромождать статью я привел только те, которые мы будем использовать сегодня, а также ещё несколько для чтобы вы могли оценить масштаб возможностей утилиты.

В функциях-действиях можно использовать различные переменные и операторы, вот несколько из них:

  • FNR — номер обрабатываемой строки в файле;
  • FS — разделитель полей;
  • NF — количество колонок в данной строке;
  • NR — общее количество строк в обрабатываемом тексте;
  • RS — разделитель строк, по умолчанию символ новой строки;
  • $ — ссылка на колонку по номеру.

Кроме этих переменных, есть и другие, а также можно объявлять свои.

Условиепозволяет обрабатывать только те строки, в которых содержатся нужные нам данные, его можно использовать в качестве фильтра, как grep. А ещё условие позволяет выполнять определенные блоки кода awk для начала и конца файла, для этого вместо регулярного выражения используйте директивы BEGIN (начало) и END (конец). Там ещё есть очень много всего, но на сегодня пожалуй достаточно. Теперь давайте перейдем к примерам.

5. Заключение

Как вы можете видеть, с помощью awk вы можете выполнять большое количество операций по обработке текста и множество других полезных вещей. Мы не вдавались в более сложные предметы, такие как предопределенные функции awk, но мы показали достаточно (как мы надеемся), чтобы вы запомнили, каким мощным инструментом является awk.

[spoiler title=»Источники»]

  • https://andreyex.ru/operacionnaya-sistema-linux/primery-komandy-awk/
  • http://rus-linux.net/MyLDP/consol/awk.html
  • https://www.ibm.com/developerworks/ru/library/l-awk1/index.html
  • https://ITProffi.ru/ispolzovanie-awk-v-linux/
  • https://losst.ru/ispolzovanie-awk-v-linux
[/spoiler]