Использование языка AWK для работы с текстом в Linux

Утилиты Linux часто повторяют принципы работы Unix. Инструменты стремятся к простоте, используют обычные текстовые файлы для ввода и вывода данных и работают по модульному принципу. Такое подражание также предоставляет огромные функциональные возможности обработки текста с помощью инструментов sed и awk.

Читайте также: Основы работы с редактором потоков Sed

Данное руководство описывает использование awk. Awk – это одновременно язык програмирования и текстовый процессор, предоставляющий несколько очень удобных способов обработки текстовых данных. Все примеры были выполнены на Ubuntu 12.04 VPS, но любая современная система Linux должна работать таким же образом.

Основной синтаксис

Команда awk включена во все современные дистрибутивы Linux по умолчанию, ее не нужно устанавливать.

Лучше всего аwk справляется с файлами, отформатированными предсказуемым образом. К примеру, эта команда особенно сильна в анализе и обработке табличных данных. Она работает путем построчного разбора всего файла.

По умолчанию для разделения полей она использует пробельные символы и символы табуляции. К счастью, большинство систем Linux используют такой формат.

Базовый формат команды awk:

awk '/поисковый_шаблон/ { действие_над_совпадениями; другое_действие; }' файл_для_анализа

Поисковый шаблон или действие можно опустить. Если действие не указано, по умолчанию команда awk выведет результат на экран, то есть, просто  выведет все совпавшие с шаблоном строки.

Если был пропущен шаблон, awk выполнит указанное действие для всех строк.

Если обе части были указаны, awk использует поисковый шаблон, чтобы вывести совпавшие с ним строки, а затем выполняет над этими строками указанное действие.

Основы работы с awk

В своей простейшей форме awk, как и cat, просто выводит все строки текстового файла на экран.

Для примера попробуйте вывести файл fstab, содержащий список существующих файловых систем:

awk '{print}' /etc/fstab
# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
#
proc            /proc           proc    nodev,noexec,nosuid 0       0
# / was on /dev/vda1 during installation
UUID=b96601ba-7d51-4c5f-bfe2-63815708aabd /               ext4    noatime,errors=remount-ro 0       1

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

awk '/UUID/' /etc/fstab
# device; this may be used with UUID= as a more robust way to name devices
UUID=b96601ba-7d51-4c5f-bfe2-63815708aabd /               ext4    noatime,errors=remount-ro 0       1

Как видите, теперь awk вывела только строки, содержащие последовательность «UUID». Можно также избавиться от посторонних строк, указав, что последовательность «UUID» должна быть расположена в самом начале строки:

awk '/^UUID/' /etc/fstab
UUID=b96601ba-7d51-4c5f-bfe2-63815708aabd /               ext4    noatime,errors=remount-ro 0       1

Аналогичным образом можно использовать часть «действие», чтобы указать, какую именно информацию нужно вывести. К примеру, чтобы вывести только первый столбец, наберите:

awk '/^UUID/ {print $1;}' /etc/fstab
UUID=b96601ba-7d51-4c5f-bfe2-63815708aabd

Также можно сослаться на каждый столбец (разделены пробелами) с помощью переменных, связанных с номером столбца. Так, на первый столбец можно сослаться, набрав $1; чтобы сослаться на всю строку, используйте $0.

Встроенные переменные и расширенный формат awk

Awk использует некоторые встроенные переменные, чтобы определять фрагменты информации при обработке текста.

Список встроенных переменных awk:

  • FILENAME: ссылается на текущий входной файл.
  • FNR: Ссылается на номер текущей записи относительно текущего вводного файла. Например, если в данный момент открыто два вводных файла, команда выведет номер записи каждого из них.
  • FS: текущий разделитель полей, который используется для обозначения каждого поля в записи. По умолчанию установлен пробел.
  • NF: количество полей в текущей записию
  • NR: номер текущей записи.
  • OFS: разделитель полей для выводимых данных. По умолчанию установлен пробел.
  • ORS: разделитель записей для выводимых данных. По умолчанию установлен символ новой строки.
  • RS: разделитель записей, отделяющий записи во входном файле. По умолчанию это символ новой строки.

Значения этих переменных можно менять в соответствии с потребностями файлов. Обычно это делается во время инициализации обработки awk.

В целом, синтаксис awk немного более сложный, чем кажется сначала. Кроме того, он содержит дополнительные блоки BEGIN и END, которые могут содержать команды, которые нужно выполнить перед или после обработки файла соответственно.

Расширенный синтаксис выглядит примерно так:

awk 'BEGIN { действие; }
/поиск/ { действие; }
END { действие; }' входной_файл

Ключевые слова BEGIN и END, на самом деле, просто конкретные совокупности условий, так же, как и параметры поиска. Они совпадают до и после обработки документа.

Это значит, что некоторые переменные блока BEGIN можно изменить. К примеру, файл /etc/passwd разделён с помощью исмволов двоеточия (:), а не пробелов. Чтобы вывести первый столбец этого файла, можно использовать:

sudo awk 'BEGIN { FS=":"; }
{ print $1; }' /etc/passwd
root
daemon
bin
sys
sync
games
man
. . .

Блоки BEGIN и END можно использовать, чтобы получить простую информацию о выведенных полях:

sudo awk 'BEGIN { FS=":"; print "User\t\tUID\t\tGID\t\tHome\t\tShell\n--------------"; }
{print $1,"\t\t",$3,"\t\t",$4,"\t\t",$6,"\t\t",$7;}
END { print "---------\nFile Complete" }' /etc/passwd
User        UID     GID     Home        Shell
--------------
root         0       0       /root       /bin/bash
daemon       1       1       /usr/sbin       /bin/sh
bin          2       2       /bin        /bin/sh
sys          3       3       /dev        /bin/sh
sync         4       65534       /bin        /bin/sync
. . .
---------
File Complete

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

Оба блока расширения – необязательны. По сути, основные действия тоже необязательны, если другая часть действий уже указана. К примеру, с awk можно работать так:

awk 'BEGIN { print "We can use awk like the echo command"; }'
We can use awk like the echo command

Условные операторы и поиск по полям

В одном из приведенных выше примеров в файле /etc/fstab была найдена последовательность «UUID». Это было просто, так как нужно было найти строку, содержащую эту последовательность в начале.

Но что, если нужно найти последовательность, расположенную в начале поля?

Можно создать тестовый файл favorite_food.txt, содержащий пронумерованный список любимых продуктов группы друзей.

echo "1 carrot sandy
2 wasabi luke
3 sandwich brian
4 salad ryan
5 spaghetti jessica" > favorite_food.txt

Чтобы вывести все слова, начинающиеся с «sa», используйте:

awk '/sa/' favorite_food.txt
1 carrot sandy
2 wasabi luke
3 sandwich brian
4 salad ryan

В выведенном результате показаны не только слова, начинающиеся с последовательности «sa». Это касается слова «wasabi», которое содержит нужную последовательность в середине; кроме того, слово «sandy» также не совсем соответствует шаблону, так как находится в другом столбце. Нужно вывести только слова, которые начинаются с «sa» во втором столбце.

Чтобы сделать это, наберите:

awk '$2 ~ /^sa/' favorite_food.txt
3 sandwich brian
4 salad ryan

Как видите, это работает должным образом.

Символ «^» говорит awk ограничить поиск началом поля. Часть «field_num ~» указывает, что искать нужно только во втором столбце.

Вывести последовательности, которые не совпадают с шаблоном, можно при помощи символа «!», указанного перед тильдой (~). Данная команда выведет все строки, которые не начинаются с «sa».

awk '$2 !~ /^sa/' favorite_food.txt
1 carrot sandy
2 wasabi luke
5 spaghetti jessica

Чтобы вывести строки, для которых верно предыдущее выражение и порядковый номер которых меньше 5, используйте условный оператор:

awk '$2 !~ /^sa/ && $1 < 5' favorite_food.txt

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

Этот оператор используется для того, чтоб проверить, что значение первого столбца меньше, чем 5.

Заключение

Данное руководство дает общее представление о том, как awk может управлять, форматировать и выборочно выводить текстовые файлы. Тем не менее, работа с Awk – достаточно широкая тема, ведь на самом деле это целый язык программирования, дополненый функциями присвоения переменных, управляющими структурами, встроенными функциями и т.п. Его можно использовать для быстрого и удобного форматирования текста скриптов.

Получить больше информации о работе awk, а также ознакомиться с gawk, современной GNU-версией awk, можно на специальных онлайн-ресурсах.

Tags: ,