Создание локальных переменных
При разработке сценариев awk не всегда удобно работать с идентификаторами полей. Лучше создать переменную, содержащую значение поля, и присвоить ей выразительное имя, чтобы в дальнейшем ссылаться на поле по имени. Подобную переменную можно получить с помощью конструкции следующего вида:
имя_переменной= $n
где n -cуществующий номер поля.
В следующем примере мы создадим две переменные: name, содержащую имена учеников (поле 1), и belts, содержащую названия поясов (поле 4). Затем будет произведен поиск учеников, обладающих желтым поясом.
$ awk '(name=$1; belts=$4; if(belts ~ /Yellow/) print name" is belt "belts}' grade.txt
P.Bunny is belt Yellow
Обратите внимание на то, что команды сценария отделяются друг от друга точкой с запятой.
Проверка значения поля
В следующем примере мы проверим, кто из учеников набрал в соревнованиях менее 27 очков. В первом варианте команды значение поля $6 непосредственно сравнивается с числом 27:
$ awk '$6 < 27' grade.txt
J.Lulu
06/99
48317
green
9
24
26
J.Troll
07/99
4842
Brown-3
12
26
26
Более универсальный способ заключается в том, чтобы перед обработкой входного файла, в процедурной части шаблона begin, создать, как в настоящей программе, набор локальных переменных с нужными значениями и ссылаться на них, когда
потребуется. Конечно, этот прием неэффективен в случае одноразовых команд, зато очень полезен в больших сценариях, так как позволяет легко вносить в них изменения. Во втором примере мы создадим переменную baseline и присвоим ей значение 27, а затем сравним с ней интересующее нас поле $6:
$ awk 'BEGIN {BASELINE=27} {if ($6 < BASELINE) print $0}' grade.txt
J.Lulu 06/99 48317 green 9 24 26
J.Troll 07/99 4842 Brown 3 12 26 26
Изменение значения числового поля
Изменяя значение поля, следует помнить о том, что содержимое входного файла на самом деле не меняется. Изменению подвергается только копия файла, которая хранится в буфере awk.
В следующем примере на экран выводятся имена учеников и их рейтинговые очки, а рейтинг ученика по имени M. Tansley уменьшается на единицу:
$ awk '{if($1="M. Tansley") $6=$6-1; print $1, $6}' grade.txt
M.Tansley 39
J.Lulu 24
P.Bunny 35
J.Troll 26
L.Tansley 30
Изменение значения текстового поля
Для изменения значения текстового поля достаточно применить к нему оператор присваивания. Следующая команда при выводе на экран добавляет к имени ученика J. Troll дополнительный инициал:
$ awk '{if($1="J. Troll") $1="J. L.Troll"; print $1}' grade.txt
M.Tansley
J.Lulu
P.Bunny
J.L.Troll
L.Tansley
He забывайте о том, что строковые константы следует заключать в двойные кавычки. Поскольку имена учеников в данном случае содержат точки, утилита awk выдаст сообщение об ошибке при отсутствии кавычек, так как точка является метасимволом и встречается в непонятном контексте.
Отображение только измененных записей
При работе с файлами большого объема часто нет необходимости отображать все записи, а достаточно вывести лишь те из них, которые подверглись изменениям. По отношению к предыдущему примеру это означает, что все команды после конструкции if следует дополнительно заключить в фигурные скобки:
$ awk '{if($1=="J. Troll") {$1="J. L.Troll"; print $1)}' grade.txt
J.L.Troll
Создание нового поля
Аналогично локальным переменным в сценарии awk можно создавать новые поля. Например, мы можем создать поле $8, содержащее разницу полей $6 и $7 в том случае, если значение в поле $7 больше, чем в поле $6:
$ awk 'BEGIN {print "Name\t\tDifference"} {if($6 < $7) \ {$8=$7-$6; print $1" \t"$8}}' grade.txt
Name Difference
L.Tansley 4
J.Lulu 2
Суммирование столбцов
Для вычисления суммарного рейтинга учеников секции мы создадим переменную tot и с помощью выражения tot+=$6 будем прибавлять к ней значение поля $6 при обработке каждой записи. По завершении обработки записей в процедурной части шаблона end итоговое значение переменной tot будет выведено на экран.
$ awk 'tot+=$6; END {print "Club student total points: " tot}' grade.txt
M.Tansley
05/99
48311
Green
8
40
44
J.Lulu
06/99
48317
green
9
24
26
P.Bunny
02/99
48
Yellow
12
35
28
J.Troll
07/99
4842
Brown-3
12
26
26
L.Tansley
05/99
4712
Brown-2
12
30
28
Club student total points: 155
Вероятно, вы заметили, что утилите awk не было дано указание выводить на экран все записи -oна сделала это сама. Причина такого поведения заключается в том, что выражение tot+=$6 относится к шаблонной части инструкции и не задает критерия отбора строк, т.е. применяется ко всем записям. А поскольку процедурная часть этого шаблона отсутствует, выполняется действие по умолчанию — команда print SO.
Если файл велик, можно не выводить на экран все записи, а лишь отобразить итог. Для этого достаточно взять выражение tot+=$6 в фигурные скобки, чтобы перенести его в процедурную часть инструкции:
$ awk '{tot+=$6}; END {print "Club student total points: " tot}' grade.txt
Club student total points: 155
Суммирование размеров файлов
При просмотре содержимого каталога часто требуется узнать общий размер всех файлов в нем, исключая файлы в подкаталогах и скрытые файлы. Алгоритм решения этой задачи таков: результаты работы команды ls -l (формирует список файлов с расширенной информацией о них; см. главу 1) направляются утилите awk, которая удаляет записи, начинающиеся с символа 'd' (признак каталога), и вычисляет сумму по 5–му столбцу (содержит размер файла).
Представленная ниже команда отображает список файлов текущего каталога (имя файла берется из 9–го столбца), указывая размер каждого из них, а в конце выводит суммарный размер файлов, накопленный в переменной tot:
$ ls -l | awk '/^[^d]/ {print $9"\t"$5; tot+=$5} END {print "total KB: "tot}' dev_pkg.fail 345 failedlogin 12416
messages
4260
зи1од
12810
utap
1856
wtap
7104
total KB: 38791
Если необходимо включить в список скрытые файлы, следует вместо команду ls -l задать команду 1s -la.
9.2.9. Встроенные переменные
Утилита awk имеет ряд встроенных переменных, которые позволяют получить подробную информацию о входном потоке и настройках awk. Значения некоторых переменных можно изменять. В табл. 9.3 кратко описаны основные переменные.
Таблица 9.3. Встроенные переменные awk
Переменная
Что содержит
ARGC
Количество аргументов в командной строке (поддерживается только: в nawk и gawk)
ARGV
Массив аргументов командной строки (поддерживается только в nawk и gawk)
ENVIRON
Массив переменных среды (поддерживается только в nawk и gawk)
FILENAME
Имя файла, обрабатываемого в текущий момент