awk может использоваться
непредсказуемым способом: системы
баз данных, различные компиляторы и
трасляторы, в дополнение к
традиционным задачам поиска
информации, обработки данных и
генерации отчетов. Программы awk
значительно короче, чем
аналогичные программы, написанные
на традиционных языках
программирования, таких как Pascal и
Си. В этом подразделе приведены
примеры, иллюстрирующие некоторые
дополнительные возможности
программ awk.
10.26.1. Генерирование отчетов
awk особенно успешно применяется
для выдачи отчетов, которые
суммируют и форматируют
информацию. Предположим, вы хотите
создать отчет из файла countries, в
котором континенты перечисляются в
алфавитном порядке и по каждому
континету страны перечисляются в
убывающем по населению порядку:
Africa:
Sudan 19
Algeria 18
Asia:
China 866
India 637
USSR 262
Australia:
Australia 14
North America:
USA 219
Canada 24
South America:
Brazil 116
Argentina 26
Так как здесь несколько задач
обработки данных, то намного легче
выполнить этот отчет в несколько
стадий. Первая: создать список
троек
"континент_страна_население",
в котором каждое поле отделяется
запятой. Это можно сделать с
помощью следующей программы triplies,
которая использует массив pop,
индексированный в форме
"континент:страна" для
сохранения количества населения
данной страны. Оператор print в секции
END этой программы создает список
троек
"континент-страна-население",
который направляется в программу
sort:
BEGIN { FS = "\t" }
{ pop[$4 ":" $1] += $3 }
END { for ( cc in pop )
print cc "":" pop[cc] | "sort -t: +0 -1 +2nr" }
Аргумент для sort заслуживает
специального внимания. Аргумент -t:
говорит sort, чтобы использовать
":" как разделитель полей.
Аргументы +0 и -1 делают первое поле
первичным ключом sort. В общем случае
+i -j делают поля i+1, i+2, ... j ключом
сортировки. Если j опущено, поля от
i+1 до конца записи используются.
Аргумент +2nr делает третье поле
(цифровое уменьшение) вторичным
ключом sort ( n - числовое, r - обратный
порядок). Относительно файла countries
эта программа выдает результат:
Africa:Sudan:19
Africa:Algeria:18
Asia:China:866
Asia:India:637
Asia:USSR:262
Australia:Australia:14
North America:USA:219
North America:Canada:24
South America:Brazil:116
South America:Argentina:26
Порядок вывода правильный, но
неверен формат. Чтобы
преобразовать формат вывода в
требуемую форму, запустите
программу format с этими данными:
BEGIN { FS = ":" }
{ if ($1 != prev) {
print "\n" $1 ":"
prev = $1
}
printf "\t%-10s %6d\n", $2, $3
}
Эта программа прерывания
управления печатает только первое
появление имени континента и
форматирует строки
"страна-население",
соответствующие этому континенту,
требуемым способом. Командная
строка:
awk -f triplies countries | awk -f format
дает требуемый отчет. В этом
примере предполагается, что
сложные задачи преобразования
данных и их форматирования могут
быть сокращены до нескольких
простых команд awk и сортировки.
10.26.2. Дополнительные примеры
10.26.2.1. Частота использования
слов
Первый пример иллюстрирует
связанные массивы для подсчета.
Предположим, вы хотите подсчитать
сколько раз каждое слово
появляется во вводе, где
"слово" - это любая непрерывная
последовательность символов,
отличных от пустого символа и
символа табуляции. Следующая
программа печатает частоту
появления слов, отсортированных в
убывающем порядке:
{ for ( w = 1; w <= NF; w++ ) count[$w]++ }
END {for( w in count) print count[w], w | " sort -nr" }
Первый оператор использует
массив count для накопления
количества появлений каждого
слова. Как только ввод будет считан,
второй оператор цикла for направляет
окончательный счетчик каждого
слова команде sort.
10.26.2.2. Накопление
Предположим вы имеете два файла
deposite и withdrawals, записи которых
содержат имя поля и количество
полей. Для каждого имени вы хотите
напечатать итог net, определяющийся
вычитанием общего вывода из общего
депозита. Баланс net может быть
вычислен следующей программой:
awk '
FILENAME == "deposits" { balance[$1] += $2 }
FILENAME == "withdrawals" { balance[$1] -= $2 }
END { for (name in balance )
print name, balance[name]
}' deposits withdrawals
Первый оператор использует
массив balance для накопления общего
количества для каждого имени в
файле deposits. Второй оператор
вычитает соответствующий вывод из
каждого общего депозита. Оператор
END печатает каждое имя с
соответствующим итогом.
10.26.2.3. Случайный выбор
Следующая функция печатает
случайные элементы k, начиная с
первого элемента массива A,
состоящего из n элементов. В
программе k - это количество входов,
необходимых для печати, n -
количество элементов, которые еще
будут исследоваться. Выбор
печатать или нет i-тый элемент
определяется тестом rand() < k/n:
function choose (A, k, n, i) {
for (i = 1; n > 0; i++)
if (rand() < k/n--) {
print A[i]
k--
}
}
}
10.26.2.4. Возможности shell
Следующая программа awk
приблизительно моделирует
возможности shell системы UNIX. Строка,
содержащая только знак "="
заново выполняет последнюю
выполненную команду. Строка,
начинающаяся с =cmd заново выполняет
последнюю команду, вызов которой
включает строку cmd. Иначе
выполняется текущая строка.
$1 == "=" { if [NR == 1]
system ( x[NR] = x [NR-1] )
else
for ( i= NR-1]; i > 0; i-- )
if ( x[i] ~ $2 ) {
system(x[NR] = x[i])
break
}
next }
/./ { system(x[NR] = $0) }
|