10.26. Примеры использования

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) }

Назад | Содержание | Вперед