ло двоеточий = 5 Число точек с запятой = 6 Число слов = 50 Число символов в словах = 150 Число предложений = 10 Средняя длина предл. = 5 (слов) Средняя длина слова = 3 6. Ввод и вывод данных в AWK-программах Ввод данных в AWK-программу определяется именем вход- ного файла в командной строке. Таких файлов может быть нес- колько, и обрабатываться AWK-программой они будут последова- тельно в том порядке, в котором указаны в командной строке, например: awk -f prog f1 f2 f3 f4 AWK-программа из файла prog будет выполняться над входным потоком записей из файлов f1, f2, f3 и f4. Здесь необходимо отметить, что предопределенная переменная NR будет иметь значение, равное порядковому номеру записи ( NR не обнуля- ется при переходе к чтению очередного файла). Пусть имеются четыре файла. Файл f1: a[1][1] a[1][2] a[1][3] a[1][4] a[2][1] a[2][2] a[2][3] a[2][4] a[3][1] a[3][2] a[3][3] a[3][4] a[4][1] a[4][2] a[4][3] a[4][4] Файл f2: b[1][1] b[1][2] b[1][3] b[1][4] b[2][1] b[2][2] b[2][3] b[2][4] b[3][1] b[3][2] b[3][3] b[3][4] b[4][1] b[4][2] b[4][3] b[4][4] Файл f3: c[1][1] c[1][2] c[1][3] c[1][4] c[2][1] c[2][2] c[2][3] c[2][4] c[3][1] c[3][2] c[3][3] c[3][4] c[4][1] c[4][2] c[4][3] c[4][4] Файл f4: - 26 - d[1][1] d[1][2] d[1][3] d[1][4] d[2][1] d[2][2] d[2][3] d[2][4] d[3][1] d[3][2] d[3][3] d[3][4] d[4][1] d[4][2] d[4][3] d[4][4] Каждый из этих файлов включает по четыре записи (по четыре поля в каждой). Другими словами, каждый файл - матрица (4*4). Допустим, необходимо получить новую матрицу с раз- мерностью (4*4), столбцы которой составлены из элементов диагоналей исходных матриц. Ниже приведен текст программы, в которой решается эта задача: { if( FILENAME != Name ) { i = 0; Name = FILENAME; } i++; if( i == 1 ) { Dig1 = Dig1 " " $1; next; } if( i == 2 ) { Dig2 = Dig2 " " $2; next; } if( i == 3 ) { Dig3 = Dig3 " " $3; next; } if( i == 4 ) Dig4 = Dig4 " " $4; } END { print( Dig1 ); print( Dig2 ); print( Dig3 ); print( Dig4 ); } В программе два правила. Первое правило не содержит селектора, следовательно, выполняется для всех входных запи- сей. Второе правило выполняется по завершению входного потока. Программа работает следующим образом: первоначально проверяется, изменилось ли имя входного файла (предопреде- ленная переменная FILENAME), затем, если не изменилось, присваивается значение соответствующего поля записи к пере- менной Dig (используется операция конкатенации старого зна- чения Dig со значением поля и присваивания Dig нового значе- ния). Переменная Name предназначена для сохранения имени входного файла. Первоначально значения переменных Name и Dig - 27 - равны пустым строкам. Важно, что мы знаем точно число запи- сей, это позволяет выделять нужные поля в записях. Допус- тим, выполняется следующая командная строка: awk -f prog f1 f2 f3 f4 >&gt; Result в файле Result будем иметь: a[1][1] b[1][1] c[1][1] d[1][1] a[2][2] b[2][2] c[2][2] d[2][2] a[3][3] b[3][3] c[3][3] d[3][3] a[4][4] b[4][4] c[4][4] d[4][4] Результат работы программы существенно связан с порядком чтения входных файлов. Если выполнить командную строку awk -f prog f4 f3 f2 f1 >&gt; Result получим: d[1][1] c[1][1] b[1][1] a[1][1] d[2][2] c[2][2] b[2][2] a[2][2] d[3][3] c[3][3] b[3][3] a[3][3] d[4][4] c[4][4] b[4][4] a[4][4] Когда возникает необходимость передать в AWK-программу значения некоторых переменных, можно воспользоваться возмож- ностью указать их в файле. Допустим, заранее не известны образцы для выделения записей файла f1. В этом случае можно создать файл f0 с описаниями образцов и, воспользовавшись значением переменной FILENAME, присвоить этим переменным нужные значения. Пусть файл f0 имеет вид: aaa bbb ccc Пусть файл f1 имеет вид: aaa bbb ccc ddd eee eee bbb ccc ddd aaa aaa fff ccc ddd eee aaa bbb ggg ttt eee Программа на AWK: - 28 - FILENAME == "f0" { pat1 = $1; pat2 = $2; pat3 = $3; next; } $1 == pat1 { print; next } $2 == pat2 { print; next } $3 == pat3 { print } После выполнения командной строки awk -f prog f0 f1 получим в файле Result: aaa bbb ccc ddd eee aaa fff ccc ddd eee aaa bbb ggg ttt eee Можно предусмотреть ввод переменных со стандартного ввода; воспользуемся тем, что переменная FILENAME для стан- дартного ввода определена как "-". Пусть файл f1 имеет вид: aaa bbb ccc ddd eee eee bbb ooo ddd aaa aaa fff ccc ddd eee qqq bbb ggg ttt eee ooo fff ggg ttt eee ccc bbb ggg ttt eee Приведенная ниже программа позволяет получить значения пере- менных с клавиатуры дисплея: BEGIN { print("Вводите значения полей:"); } FILENAME == "-" { pat1 = $1; pat2 = $2; pat3 = $3; } FILENAME == "f1" { if($1 == pat1) { print($0); next } if($2 == pat2) { print($0); next } if($3 == pat3) { print($0);} } После запуска на выполнение следующей командной строки awk -f prog - f1 - 29 - программа будет ждать ввода с клавиатуры дисплея (завершить ввод необходимо символом конец файла - CTRL/D). Например: Вводите значения полей: qqq fff ooo CTRL/D eee bbb ooo ddd aaa aaa fff ccc ddd eee qqq bbb ggg ttt eee ooo fff ggg ttt eee Как уже говорилось раньше, вывод AWK-программы направ- ляется на экран дисплея, если не было указано другое. Существует возможность направить вывод по нескольким каналам непосредственно из AWK-программы, для этого можно воспользо- ваться стандартными средствами системы ДЕМОС. Например: print( $0 ) >&gt; "file"; запись будет направлена в файл с именем ./file; print( $0 ) >&gt;>&gt; "file"; запись будет дописана в ./file; print( $0 ) >&gt; $2; запись будет направлена в файл с именем, равным содержимому ее второго поля. Существует возможность из AWK-программы направить вывод в конвейер, например: { print($0) | "tr ' ' '\n' | sort "; } Здесь запись будет направлена команде tr, которая заменит пробел символом '\n', затем отсортирована командой sort. Пусть выполнена следующая командная строка: awk -f prog - после ввода с клавиатуры нескольких записей dfa nrk klm njf rty xvz saa ass dcf vfr klm ttr CTRL/D получим: - 30 - ass dcf dfa klm klm njf nrk rty saa ttr vfr xvz Вывод результата работы конвейера осуществляется по заверше- нию чтения последней входной записи. Канал вывода в примере совпадает с каналом стандартного вывода, но его можно пере- определить на любой файл. В одной AWK-программе можно одновременно определить несколько каналов вывода, число которых зависит от числа файлов, разрешенных для одновременного использования. Это число устанавливается при генерации операционной системы ДЕМОС. Для вывода данных в AWK-программе предназначен оператор print. До настоящего момента мы применяли лишь одну форму использования этого оператора: print(список_фактических_параметров); Круглые скобки использовались раньше для того, чтобы не отв- лекать читателя, знакомого с языком программирования Си, - их можно не указывать. Существуют и другие формы использова- ния этого оператора: print; выводится вся запись; print $1, $2; значения полей выводятся через пробел; print $1 $2; выводится конкатенация значений полей. При необходимости управления форматом вывода можно использовать библиотечную функцию printf, синтаксис и результат работы которой такие же, как и в языке Си. 7. Использование встроенных функций - 31 - Интерпретатор awk включает набор встроенных функций, которые можно использовать в действиях правил. Существуют два способа вызова встроенных функций: имя_функции(список_фактических_параметров) имя_функции Во втором случае в качестве фактического параметра применя- ется вся текущая запись. Как обычно, значение функции подс- тавляется в выражение в том месте, где определен вызов. Имеются следующие встроенные функции: length(выражение) значением выражения является строка. Функция length возвращает длину строки, например: print( length($1 " " $2)); будет напечатана длина строки, полученной конкатенацией поля $1, пробела и поля $2. Форма без аргумента возв- ращает длину записи. exp(выражение) возвращает экспоненту от выражения. log(выражение) возвращает натуральный логарифм выражения. sqrt(выражение) возвращает значение квадратного корня от выражения. int(выражение) возвращает целую часть числа, равного значению выраже- ния. substr(S, M, N) возвращает часть строки S, начинающуюся от позиции M и имеющую длину не более N символов. Символы в строке S нумеруются с 1. Если аргумент N не указан, возвраща- ются все символы от M до конца строки. string = substr( $0, 12, 20); String будет включать 9 символов (с 12 по 20) текущей записи. index(As, Ps) возвращает номер позиции, с которой строка Ps совпадает со строкой As. Если совпадения нет, возвращается 0. - 32 - sprintf(формат, выражение, ...) возвращает строку, выведенную по формату. Синтаксис функции и результат работы аналогичны функции sprintf в библиотеке языка программирования Си. split( S, Name, разделитель ) строка S разбивается на поля, значения которых присваи- ваются элементам массива Name. Значением первого эле- мента Name[1] будет содержимое первого выделенного поля, значением второго элемента Name[2] - второго выделенного поля и так далее. Если не указан раздели- тель полей, используется значение предопределенной переменной FS. Функция split возвращает число выделен- ных полей. Рассмотрим пример. Пусть имеется файл f1 aaa bbb ccc# ddd# eee fff# ggg ttt# ggg eee# ccc ddd sss# yyy и AWK-программа { i = split( $0, Name, "#"); for(j = 1; j <&lt;= i; j++) print( "Name["j"] =", Name[j]); } после выполнения командной строки awk -f prog f1 получим: Name[1] = aaa bbb ccc Name[2] = ddd Name[3] = eee fff Name[4] = ggg Name[1] = ttt Name[2] = ggg eee Name[3] = ccc ddd sss Name[4] = yyy - 33 - СОДЕРЖАНИЕ Аннотация ......................................... 2 1. Принципы работы интерпретатора awk ................ 3 2. Переменные, выражения и присваивания в AWK- программах ........................................ 7 3. Структура AWK-программы ........................... 13 4. Селекторы ......................................... 16 5. Действия .......................................... 22 6. Ввод и вывод данных в AWK-программах .............. 26 7. Использование встроенных функций .................. 31 - 34 -