| Каталог | Индекс раздела |
| Назад | Оглавление | Вперед |
1. Язык программирования awk
1.1. Структура программы
1.2. Лексемы
1.2.1. Числовые константы
1.2.2. Текстовые константы
1.2.3. Ключевые слова
1.2.4. Идентификаторы
1.2.5. Знаки операций
1.2.6. Лексемы для работы с записями и полями
1.2.6.1. Разделитель записей
1.2.6.2. Разделитель полей
1.2.6.3. Записи, состоящие из нескольких строк
1.2.6.4. Выходные разделители записей и полей
1.2.7. Комментарии
1.2.8. Лексемы, используемые для группировки
1.3. Первичные выражения
1.3.1. Числовые константы
1.3.2. Текстовые константы
1.3.3. Переменные
1.3.4. Функции
1.4. Термы
1.4.1. Бинарные термы
1.4.2. Унарные термы
1.4.3. Переменные с приращением
1.4.4. Термы, заключенные в скобки
1.5. Выражения
1.5.1. Конкатенация термов
1.5.2. Выражения-присваивания
3. Ввод/вывод
3.1. Запуск программ на выполнение
3.2. Ввод: записи и поля
3.3. Ввод из файла
3.4. Ввод из командной строки
3.5. Вывод на печать
3.6. Вывод в различные файлы
3.7. Вывод в каналы
4. Шаблоны
4.1. BEGIN и END
4.2. Выражения сравнения
4.3. Регулярные выражения
4.4. Комбинации шаблонов
4.5. Шаблоны-диапазоны
5. Действия
5.1. Переменные, выражения и присваивания
5.2. Инициализация переменных
5.3. Переменные-поля
5.4. Конкатенация цепочек
5.5. Специальные переменные
5.6. Типы данных
5.7. Массивы
6. Специфические возможности
6.1. Встроенные функции
6.2. Управляющие конструкции
6.3. Генерация отчетов
6.4. Взаимодействие с shell'ом
6.5. Многомерные массивы
awk(1) - это язык программирования, предназначенный для обработки файлов. Цель его разработки - облегчить постановку и решение многих задач, связанных с переработкой текстовой информации. awk выполняет следующие действия:
В первой части главы в общих чертах излагается синтаксис awk'а.
Затем, начиная с раздела ПРИМЕНЕНИЕ AWK'А, приводится несколько
примеров, демонстрирующих использование предоставляемых языком
возможностей.
awk-программа - это последовательность операторов следующего
вида:
awk обрабатывает набор входных файлов. Основной
операцией awk'а
является просмотр входных строк в порядке их поступления. Каждую
строку awk пытается сопоставить с описанным в
awk-программе
шаблоном. Если сопоставление оказалось успешным, выполняется
соответствующее этому шаблону действие. Таким же образом к данной
входной строке применяются и все остальные содержащиеся в
awk-программе операторы. После того, как проверены все шаблоны,
awk переходит к следующей входной строке, причем
awk-программа
снова выполняется с начала.
В awk-операторах могут отсутствовать как шаблоны, так и
действия, но не обе части одновременно. Отсутствие действия
эквивалентно предписанию распечатать строку. Если указано только действие,
оно выполняется для каждой входной строки. Пустая
awk-программа не делает ничего. Поскольку
оба компонента оператора
являются необязательными, действия должны заключаться в фигурные
скобки, чтобы отличить их от шаблонов.
Например, awk-программа
выводит все входные строки, содержащие символ x.
awk-программа имеет следующую структуру:
Секция BEGIN выполняется перед обработкой входных строк, секция
END - после того, как все исходные данные обработаны. Основная
секция выполняется для каждой входной строки. Ключевые слова
BEGIN и END являются
на самом деле шаблонами специального вида,
которые распознаются awk'ом.
Все awk-программы составляются из лексем следующих восьми видов:
К числовым относятся десятичные константы и константы с плавающей
точкой. Десятичная константа - это непустая последовательность
цифр, которая может содержать десятичную точку (не более
чем одну); например: 12, 12.,
1.2, .12. Константа с плавающей
точкой состоит из десятичной константы, за которой следуют символы
e (либо E), необязательный знак +
или - и непустая последовательность цифр; например:
12e3, 1.2e3, 1.2e-3,
1.2E+3. Максимально допустимые размер и точность числовых
констант машинно-зависимы.
Текстовая константа - это цепочка из нуля или большего числа
символов, заключенная в двойные кавычки; например: ",",
"a", "ab", "12".
Чтобы включить в цепочку сам символ двойной кавычки,
перед ним надо поставить знак \:
"He said, \"Sit!\"". Чтобы
включить в цепочку символ перевода строки, в соответствующем
месте надо указать \n. Никаких других управляющих
последовательностей не требуется. Текстовые константы могут иметь
(практически) любую длину.
Следующая таблица содержит используемые в awk'е ключевые слова:
Идентификаторы в языке awk служат для того, чтобы обозначать
переменные и массивы. Идентификатор - это последовательность
букв, цифр и подчеркиваний, начинающаяся с буквы или подчеркивания.
Прописные и строчные буквы различаются.
awk предоставляет арифметические, логические операции, операции
сравнения и присваивания, аналогичные соответствующим операциям
языка программирования C, а также операции сопоставления с шаблонами,
заданными регулярными выражениями, аналогичные тем, ко-
торые используются в egrep(1).
Следующие таблицы содержат описание операций языка awk:
Операции присваивания:
1.1. Структура программы
шаблон { действие }
шаблон { действие }
. . .
/x/ { print }
1.2. Лексемы
1.2.1. Числовые константы
1.2.2. Текстовые константы
1.2.3. Ключевые слова
BEGIN break log
END close next
FILENAME continue number
FS exit print
NF exp printf
NR for split
OFS getline sprintf
ORS if sqrt
OFMT in string
RS index substr
int while
length
1.2.4. Идентификаторы
1.2.5. Знаки операций
| знак операции | использование | описание | = | присвоить | += | сложить и присвоить | X += Y аналогично X = X+Y | -= | вычесть и присвоить | X -= Y аналогично X = X-Y | *= | умножить и присвоить | X *= Y аналогично X = X*Y | /= | разделить и присвоить | X /= Y аналогично X = X/Y | %= | вычислить остаток и присвоить | X %= Y аналогично X = X%Y | ++ | префиксное и постфиксное увеличение | ++X и X++ аналогично X = X+1 | -- | префиксное и постфиксное уменьшение | --X и Y-- аналогично X = X-1 |
Арифметические операции:
| знак операции | описание | + | унарный и бинарный плюс | - | унарный и бинарный минус | * | произведение | / | частное | % | остаток от деления | (...) | группировка |
Операции сравнения:
| знак операции | описание | < | меньше | <= | меньше или равно | == | равно | != | не равно | >= | больше или равно | > | больше |
Логические операции:
| знак операции | описание | && | и | || | или | ! | отрицание |
Операции сопоставления:
| знак операции | описание | ~ | сопоставляется | !~ | не сопоставляется |
$0 - это специальная переменная, чье значение совпадает со значением текущей входной записи. $1, $2 и т.д. - специальные переменные, чьи значения совпадают со значениями соответственно первого, второго и т.д. полей текущей входной записи. Ключевое слово NF (Number of Fields) обозначает специальную переменную, значение которой равно числу полей в текущей входной записи. Таким образом, значение $NF совпадает со значением последнего поля в текущей записи. Отметим, что нумерация полей в записи начинается с 1, а число полей может изменяться от записи к записи. В действиях, относящихся к шаблонам BEGIN и END, использование перечисленных лексем не имеет смысла, поскольку для этих действий не определена текущая входная запись.
Ключевое слово NR (Number of Records) обозначает специальную
переменную, значение которой равно числу входных записей, прочитанных
к данному моменту. Первая прочитанная входная запись
имеет номер 1.
Ключевое слово RS (Record Separator) - это специальная
переменная, значение которой равно текущему разделителю записей.
Первоначально значение RS устанавливается равным символу перевода
строки; это означает, что соседние входные записи отделяются
одна от другой переводами строк. Значение переменной RS можно
заменить на любой символ c, выполнив в действии оператор
присваивания RS = "c".
Ключевое слово FS (Field Separator) - это специальная
переменная, значение которой равно текущему разделителю полей.
Первоначальное значение FS - пробел; это означает, что поля
отделяются произвольными непустыми последовательностями пробелов и
табуляций. Значение переменной FS можно заменить на любой
одиночный символ c, выполнив в действии оператор присваивания
FS = "c" или указав в командной
строке необязательный аргумент -Fc.
Два значения c имеют особый смысл. Присваивание FS = " " делает
разделителями полей пробелы и табуляции, а аргумент командной
строки F\t - табуляции.
Если в качестве разделителя полей используется символ, отличный
от пробела, считается, что с каждой стороны от разделителя имеется
по полю. Например, если разделитель полей равен 1, то
запись 1XXX1 состоит из трех полей. Первое и третье - пустые.
Если разделитель полей - пробел, поля отделяются друг от друга
пробелами и табуляциями и ни одно из NF полей не может быть
пустым.
Присваивание RS = " " делает разделителем записей пустую
строку, а разделителем полей - непустую последовательность из
пробелов, табуляций и, возможно, переводов строк. Такое определение
не допускает, чтобы первое или последнее поля в записи были
пустыми.
Значение переменной OFS (Output Field Separator) задает
выходной разделитель полей; действие print помещает его между
полями. После каждой записи print помещает символ, являющийся
значением переменной ORS (Output Record Separator). Первоначально
ORS устанавливается равным переводу строки,
а OFS - пробелу.
Данные значения можно заменить любыми другими цепочками при по-
мощи присваиваний, например, ORS = "abc"
и OFS = "xyz".
Комментарий открывается символом # и заканчивается переводом
строки. Пример:
Комментарий можно добавить в конце любой строки awk-программы.
Обычно в awk'е лексемы отделяются друг от друга непустыми
последовательностями пробелов, табуляций и переводов строк, а также
другими пунктуационными символами, такими как запятые и точ-
ки с запятой. В фигурные скобки, {...}, заключаются действия, в
наклонные черты, /.../, - шаблоны, заданные регулярными
выражениями, в двойные кавычки,
"...", - текстовые константы.
В awk'е шаблоны и действия составляются из выражений. Первичные
выражения - это основные "строительные блоки" для выражений; к
первичным выражениям относятся:
Каждое выражение имеет как числовое, так и текстовое значение;
одно из них обычно является предпочтительным. Правила, по которым
определяется предпочтительное значение выражения, излагаются ниже.
Формат числовых констант описан ранее, в разделе Лексемы. Значения
таких констант хранятся в виде вещественных чисел. Текстовое
значение числовой константы определяется естественным образом.
Предпочтительным является числовое значение. Следующая
таблица содержит примеры значений числовых констант:
1.2.6.1. Разделитель записей
1.2.6.2. Разделитель полей
1.2.6.3. Записи, состоящие из нескольких строк
1.2.6.4. Выходные разделители записей и полей
1.2.7. Комментарии
# This line is a comment
1.2.8. Лексемы, используемые для группировки
1.3. Первичные выражения
1.3.1. Числовые константы
| Числовая константа | Числовое значение | Текстовое значение |
| 0 | 0 | 0 |
| 1 | 1 | 1 |
| .5 | 0.5 | .5 |
| .5e2 | 50 | 50 |
Формат текстовых констант описан ранее, в разделе Лексемы. Числовое значение текстовой константы равно 0, если только цепочка, заключенная в двойные кавычки, не является записью числовой константы. В этом случае числовое значение определяется естественным образом. Предпочтительным является текстовое значение, которое всегда совпадает с самой константой. Следующая таблица содержит примеры значений текстовых констант:
| Текстовая константа | Числовое значение | Текстовое значение |
| "" | 0 | пусто |
| "a" | 0 | a |
| "XYZ" | 0 | XYZ |
| "o" | 0 | 0 |
| "1" | 1 | 1 |
| ".5" | 0.5 | .5 |
| ".5e2" | 50 | .5e2 |
Переменная - это одна из следующих конструкций:
идентификатор
идентификатор [ выражение ]
$терм
Числовое значение любой неинициализированной переменной равно 0, а текстовое значение - пустой цепочке.
Идентификатор, указанный сам по себе, - это простая переменная. Переменная вида идентификатор[выражение] представляет элемент ассоциативного массива, названного при помощи идентификатора. Текстовое значение выражения используется в качестве индекса в массиве. Предпочтительное значение переменных идентификатор и идентификатор[выражение] определяется, исходя из контекста.
Переменная $0 обозначает текущую входную запись. Ее текстовое и числовое значения совпадают со значениями текущей записи. Если текущая входная запись представляет число, то числовое значение $0 равно данному числу, а текстовое значение - соответствующей цепочке символов. Предпочтительным значением $0 является текстовое, если только текущая входная запись не представляет число. $0 нельзя изменить при помощи присваивания.
Переменные $1, $2, ... обозначают первое, второе и т.д. поля. Текстовое и числовое значения $i (1 <= i <= NF) совпадают со значениями i-го поля текущей записи. Так же, как и для $0, если i-е поле представляет число, то числовое значение $i равно данному числу, а текстовое значение - соответствующей цепочке символов. Предпочтительным значением $i является текстовое, если только это поле не представляет число. $i можно изменить при помощи присваивания; соответственно изменяется и значение $0.
В общем случае, $терм
обозначает входную запись, если терм имеет числовое значение 0, и
i-е поле, если целая часть числового
значения терма равна i. Если
NF < i <= 100, $i ведет себя так
же, как неинициализированная переменная. Манипуляции с $i при
i > NF не изменяют значения NF.
В awk'е имеется ряд встроенных функций, реализующих часто
используемые арифметические операции и операции над цепочками
символов. Ниже перечислены арифметические операции:
Арифметические функции (exp, int,
log, sqrt) вычисляют, соответственно,
экспоненту, целую часть, натуральный логарифм и
квадратный корень числового значения выражения. (выражение) может
быть опущено, в таком случае функция применяется к $0.
Предпочтительным считается числовое значение арифметической
функции.
Операции над цепочками символов:
Выполнение функции getline приводит к тому, что текущая входная
запись заменяется на следующую входную запись. Функция возвращает
1, если следующая входная запись существует, и 0, если ее
нет. Значение переменной NR обновляется.
Функция index (e1, e2) по текстовым
значениям выражений e1 и e2
находит первое вхождение цепочки e2 в
e1 и возвращает номер начальной позиции. Если
e2 не входит в e1, функция index
возвращает 0. Пример:
Функция length без аргументов возвращает число символов в
текущей входной записи. Если указан аргумент-выражение, length (e)
возвращает число символов в текстовом значении e. Пример:
Функция split (e, array, sep) разбивает текстовое значение
выражения e на поля, которые помещаются затем в
array[1], array[2], ...
array[n]; в качестве разделителя полей используется
текстовое значение аргумента sep. Результат, возвращаемый
функцией, равен числу обнаруженных полей. Если третий аргумент опущен,
функция split в качестве разделителя полей использует
текущее значение FS. Например, после обращения
a[1], a[2], ... a[n] -
это та же самая последовательность, что
и $1, $2, ... $NF.
Функция sprintf (f, e1, e2, ...) преобразует текстовые значения
выражений e1, e2, ...
в соответствии с форматом, специфицированным
текстовым значением выражения f. Соглашения об управлении
форматом такие же, как и для функции printf(3S) в языке
программирования C (исключение: не допускается использование
символа * для обозначения ширины поля или точности).
Функция substr (string, pos) возвращает окончание цепочки
символов string, начиная с позиции pos.
Функция substr (string, pos, length) возвращает
подцепочку аргумента string, начинающуюся с позиции
pos и имеющую длину length. Если длина
pos+length
больше, чем длина аргумента string, то оба варианта
substr эквивалентны. Пример:
Значения аргумента pos, меньшие 1, принимаются равными 1.
Отрицательное или нулевое значение аргумента length приводит
к пустому результату. Предпочтительным для функций
sprintf и substr
является текстовое значение. Предпочтительное значение
остальных функций - числовое.
Различные арифметические операции, применяемые к первичным
выражениям, образуют более крупные синтаксические элементы,
называемые термами. Все арифметические вычисления выполняются над
вещественными числами. Терм имеет одну из следующих форм:
В терме вида
биноп может быть одной из пяти арифметических
операций +, -, *
(умножение), / (деление), % (остаток).
Бинарная операция применяется к числовым значениям операндов
терм1 и терм2, результат
также имеет соответствующее числовое значение, которое является
предпочтительным, но его можно интерпретировать и как текстовое
(см. пункт Числовые константы). Операции *, /
и % имеют более
высокий приоритет, чем + и -. Все операции левоассоциативны.
уноп может быть унарным + или
-. Унарная операция применяется к
числовому значению операнда терм,
результат имеет соответствующее числовое значение, которое
является предпочтительным, однако его можно интерпретировать и
как текстовое. Унарные операции
+ и - имеют более высокий приоритет,
чем *, / и %.
Переменная с приращением имеет одну из следующих форм:
Терм ++пер имеет значение
пер+1, а по своему действию эквивалентен
присваиванию пер = пер+1. Аналогично,
терм --пер имеет
значение пер-1; он эквивалентен присваиванию
пер = пер-1. Далее, терм
пер++ имеет значение пер
и эффект присваивания пер = пер+1, а терм
пер-- имеет значение пер
и эффект присваивания
пер = пер-1. Предпочтительным значением
переменной с приращением является числовое.
Для группировки термов используются скобки.
Выражения в awk'е имеют одну из следующих форм:
В выражении вида терм терм ...
текстовые значения термов конкатенируются. Предпочтительным
значением результата считается
текстовое. Конкатенация термов имеет меньший приоритет, чем бинарные
+ и -. Например, выражение
имеет текстовое (и числовое) значение 37.
Выражение-присваивание имеет следующий вид:
где присвоп - одна из шести операций присваивания:
Предпочтительным считается то же значение пер,
что и предпочтительное значение выражения.
В результате присваивания вида
числовое и текстовое значение пер становятся
равными соответствующим значениям выражения. Присваивание
эквивалентно присваиванию
где оп - одна из операций +,
-, *, /, %.
Операции присваивания
правоассоциативны и имеют меньший приоритет, чем любая другая
операция. Так, выражение a += b *= c-2 эквивалентно
последовательности присваиваний
Задача оставшейся части данной главы - показать синтаксические
конструкции awk'а в действии. Разделы соответствуют следующим
рассматриваемым вопросам:
Есть два способа запустить на выполнение awk-программу,
состоящую из операторов вида шаблон {действие}:
1. Если программа короткая (одна-две строки), зачастую проще
всего указать программу в качестве первого аргумента командной
строки:
где программа - это awk-программа,
которую надо выполнить, а
имя-файла... -
необязательный аргумент, определяющий входной
файл (файлы). Отметим, что одинарные кавычки, в которые заключен
текст программы, нужны для того, чтобы shell воспринял всю
эту цепочку (программу) как первый аргумент команды awk.
Например, чтобы выполнить над файлом file1
awk-программу
надо передать shell'у команду
Если входной файл не специфицирован, awk ожидает исходные
данные со стандартного ввода, stdin. Кроме того, можно
специфицировать, что stdin будет одним из входных файлов; для этого в
командной строке указывается символ -. Командная строка
вызывает сначала обработку файла1,
а затем - стандартного ввода.
2. Если, напротив, программа длинная, или если Вы хотите сохранить
ее для того, чтобы использовать впоследствии, удобно поместить
программу в отдельный файл, и указать awk'у имя файла,
из которого ее надо брать. Это можно сделать, использовав в командной
строке опцию -f:
Здесь имя_программы указывает файл,
содержащий awk-программу, а
имя_файла ... - необязательный
аргумент, определяющий входной
файл (файлы), среди которых, как сказано выше, может быть стандартный ввод.
Проиллюстрируем альтернативные способы запуска на обработку
awk-программ. Выполнение shell'ом командной строки
приводит к выдаче на стандартный вывод
Эту же awk-программу можно выполнить, поместив ее текст
в файл awkprog, а затем набрав в shell'е команду
Результат будет тот же.
awk читает входные записи по одной. Если разделитель записей не
переустановлен, запись - это последовательность символов, начиная
с той, на которой остановился ввод, и до символа перевода
строки либо до конца файла. После того, как цепочка символов
считана, она присваивается переменной $0.
Прочитав запись, awk разбивает ее на поля, из которых она
составлена. Если разделитель полей не переустановлен, полем
является цепочка символов, отделенная пробелами или табуляциями.
В качестве примера рассмотрим файл countries. Данный файл состоит
из строк, содержащих площадь (в тысячах квадратных миль),
население (в миллионах человек) и континент для десяти крупнейших
по площади стран мира. (Данные взяты на 1978 год; Россия
отнесена к Азии.)
Широкие промежутки между колонками при первоначальном вводе заданы
табуляциями; слова "North" ("South") и
"America" отделяется одиночным пробелом. Данный файл
будет использоваться в этой главе в качестве исходного
во многих awk-программах, он типичен
для того рода информации, для обработки которой лучше всего
приспособлен awk (смесь слов и чисел, организованных в колонки
или поля, разделенные пробелами либо табуляциями).
Каждая из строк файла countries состоит из четырех или пяти
слов, если считать, что поля разделяются пробелами и/или табуляциями,
как и подразумевается в awk'е по умолчанию, если не
задано противное. В приведенном примере первой записью является
После того, как эта запись прочитана awk'ом, она присваивается
переменной $0. Если требуется сослаться на всю запись целиком,
это делается при помощи $0. Например, действие
распечатывает всю запись.
Поля, принадлежащие записи, присваиваются переменным
$1, $2, $3
и т.д.; это означает, что в awk-программе для обращения к
первому полю текущей записи используется переменная $1,
для обращения ко второму полю - переменная $2,
для обращения к i-ому
полю - переменная $i. Так, в приведенном выше примере (файл
countries) для первой записи:
Чтобы напечатать континент, затем название страны, и наконец,
численность населения, можно использовать следующую команду:
Можно заметить, что она породит не совсем тот вывод, который
требуется, поскольку по умолчанию разделителем полей считается
не только табуляция, но и пробел. Неудобство состоит в том, что
South America и North America
содержат пробел. Поэтому правильнее будет использовать команду
Ранее, в разделе Запуск программы на выполнение, уже говорилось,
что для того, чтобы задать awk-программу, которую требуется
выполнить, можно либо вставить ее, заключив в одинарные
кавычки, в командую строку, либо поместить в файл, а в командной
строке указать имя этого файла, поместив перед ним флаг -f.
Кроме того, в командной строке можно устанавливать значения переменных.
В awk'е значения переменным можно присваивать
внутри awk-программы. Поскольку типы переменных
не описываются, переменная
создается просто посредством обращения к ней. Пример присваивания
переменной нового значения:
Данный оператор awk-программы присваивает
переменной x значение
5. Такой вид присваивания можно задать и в командной строке -
это еще один способ указать исходные данные для awk-программы.
Например, команда
будет распечатывать значение 5 после прочтения очередной записи.
Знак - в конце командной строки необходим для того, чтобы
указать, что исходные данные надо брать со стандартного ввода,
а не из файла с именем x=5. После ввода команды пользователь
должен ввести исходные данные, завершив их сомволом CTRL+D.
Если исходные данные берутся из файла (например, с именем
file1), команда должна выглядеть так:
Если необходимо изменить разделитель полей или разделитель записей,
это также можно сделать в командной строке, как в следующем примере:
В данном примере разделитель записей устанавливается равным
символу :. В результате программа, содержащаяся в
файле awkprog, обрабатывает записи, разделенные
не символами перевода
строки, а двоеточиями; исходные данные берутся из файла file1.
Подобным же образом в командной строке можно изменить разделитель полей.
Предусмотрена специальная опция, -Fx; если она указана,
значение разделителя полей изменяется с пробела или табуляции на
символ x. Например, командная строка
заменяет разделитель полей на символ :. Отметим, что если
разделитель полей явно установлен равным табуляции (то есть при
помощи опции -F или
посредством присваивания переменной FS),
пробелы не считаются разделителями полей. Однако обратное не
верно: даже если разделитель полей явно установлен равным пробелу,
табуляции тем не менее считаются разделителями полей.
Действию может не соответствовать шаблон; в таком случае действие
выполняется для всех строк, как следующая простая программа
распечатки:
Это одно из простейших действий, выполняемых awk'ом. Оно выдает
каждую строку на печать. Полезнее бывает печатать не всю строку,
а одно или несколько полей. Например, при использовании
файла countries, описанного ранее, командная строка
распечатывает название и население стран:
Точка с запятой в конце списка операторов необязательна. awk
допускает как действие
Эти два действия эквивалентны. Однако, если требуется поместить
два awk-оператора в одну строку awk-текста,
точка с запятой необходима. Например, число 5 можно напечатать так:
Скобки для оператора print также необязательны. Действие
Аргументы оператора print, разделенные запятыми, при печати
разделяются текущим выходным разделителем полей (обычно пробелом,
даже если входные поля разделяются табуляциями). OFS - это
еще одна специальная переменная, которую может переустановить
программист. (Полностью все такие переменные перечисляются ниже.)
print может также выводить на печать цепочки, определенные
непосредственно в awk-программах, например
Как уже было сказано, awk предоставляет несколько специальных
переменных, значениями которых бывает удобно управлять, например,
FS и RS. В следующем
примере вводятся еще две специальные
переменные. NR и NF имеют
целочисленные значения, равные соответственно
номеру текущей прочитанной записи и числу полей в
ней. Так, действие
для каждой записи выводит на печать ее номер, число полей в
ней, а затем саму запись. Применение этой программы к файлу
countries дает следующий результат:
Программа
выводит на печать
Этот пример демонстрирует полезный прием: как приписать к элементам
списка их последовательные номера. Оператор print без
аргументов печатает текущую входную запись. Чтобы напечатать
пустую строку, надо использовать
awk предоставляет также оператор printf,
позволяющий программисту самостоятельно задавать требуемый
формат вывода. Для распечатываемых числовых значений
print использует по умолчанию
формат %.6g. Оператор
преобразует указанные в списке аргументов выражения
в соответствии
со спецификацией, задаваемой цепочкой формат,
и распечатывает
их. Оператор printf практически идентичен функции
printf(3S) из C-библиотеки. Например, действие
распечатывает $1 как цепочку из 10 символов (выравненную по
правому краю). Второе и третье поля (6-значные числа) образуют
аккуратную таблицу, состоящую из двух колонок:
Оператор printf не порождает автоматически никаких выходных
разделителей полей или переводов строк. Программист должен добавить
их самостоятельно, как это сделано в данном примере.
Можно указывать управляющие символы \n,
\t, \b (забой), \r
(возврат каретки).
Есть еще одна, третья ситуация, в которой может иметь место выдача на
стандартный вывод. Это происходит, когда в awk-операторе
не специфицировано действие, а только шаблон. В таком случае
распечатывается запись $0 целиком. Например, программа
распечатывает все записи, содержащие символ x.
Вывод на печать сопровождается использованием двух специальных
переменных, OFS и ORS.
По умолчанию они устанавливаются равными,
соответственно, пробелу и символу перевода строки. Переменная
OFS выдается на стандартный вывод, когда в списке аргумен-
тов оператора print встречается запятая. Например, оператор:
выводит
Однако, если запятой нет:
результат будет таким:
Чтобы вывести запятую, можно либо явно указать ее в операторе
print:
либо в секции BEGIN переопределить OFS:
В обоих случаях результатом будет:
Отметим, что при печати $0 выходной разделитель
полей не используется.
shell позволяет переназначать стандартный вывод в файл. awk
также позволяет направить вывод во многие различные файлы, причем
это можно сделать внутри awk-программы. Вернемся к входному
файлу countries. Допустим, требуется вывести всю информацию о
странах из Азии в файл, называемый ASIA, всю информацию о
странах из Африки в файл AFRICA, и т.д. Это можно сделать при
помощи следующей awk-программы:
Операторы, управляющие последовательностью вычислений, обсуждаются позднее.
В общем случае можно направить вывод в файл, указав его имя
после оператора print или printf. В операторе вида
имя_файла задает файл, в который
направляются данные. У оператора могут быть
указаны произвольные допустимые аргументы.
Подчеркнем, что имя файла заключается в кавычки. При отсутствии
кавычек имена файлов трактуются как переменные, которые могут
оказаться неинициализированными; в таком случае весь вывод направляется
в stdout, если он не переназначен в командной строке.
Если вместо > указать >>,
вывод будет добавлен в конец файла, а
не заменит его содержимое. Отметим, что существует ограничение
на максимальное число файлов, в которые можно таким образом
направить вывод. Сейчас оно равно десяти.
Вывод можно направить не только в обычный файл, но и в канал.
Пример:
где mary - имя, под которым пользователь входит в систему.
Любая запись со вторым полем, равным XX, отправляется
пользователю mary в виде почты. awk
ждет, пока не выполнится программа
целиком, а затем выполняется команда, соединенная с ней каналом
[в данном случае - команда mailx(1)]. Программа
выделяет из каждой входной записи первое поле, сортирует эти
поля и затем распечатывает их.
Еще один пример использования каналов - следующая общеупотребимая
конструкция, гарантирующая, что весь вывод обязательно будет
направлен на Ваш терминал:
Во всех операторах вывода, включающих переназначение вывода,
файлы или каналы идентифицируются по именам, однако создаются
или открываются они только один раз за время выполнения программы.
Шаблоны указываются перед действиями и играют роль фильтров,
определяющих, должны ли действия выполняться. В качестве шаблонов
используется множество различных конструкций:
Ключевое слово BEGIN является специальным шаблоном,
сопоставляющимся с началом исходных данных перед тем, как считывается
первая запись. Ключевое слово END - специальный шаблон,
сопоставляющийся с концом исходных данных после того, как обработана
последняя строка. Таким образом, BEGIN
и END дают возможность
перехватить управление до и после обработки исходных данных,
чтобы выполнить инициализационные и заключительные действия.
В следующем примере шаблон BEGIN используется для того, чтобы
вывести заголовки столбцов. Программа
порождает такой текст:
Формат, в котором выводятся заголовки, не очень хорош; в случаях,
когда важно качество внешнего представления, обычно используется
printf - он больше подходит для такой задачи.
Напомним также, что секцию BEGIN удобно использовать для
переустановки специальных переменных, в частности
FS и RS. Пример:
В этой программе FS устанавливается в секции
BEGIN равным табуляции, в результате чего все записи
в файле countries содержат
ровно четыре поля. Рекомендуется указывать BEGIN первым в
последовательности шаблонов, а END - последним.
Произвольные выражения, включающие сравнения цепочек символов
или чисел, являются допустимыми шаблонами awk'а. Например, если
требуется распечатать информацию только о странах, население
которых превышает 100 миллионов, можно использовать шаблон
Простая awk-программа, состоящая из одного этого шаблона без
всякого действия, распечатает только те записи, значение
третьего поля в которых больше 100:
Чтобы напечатать названия стран, расположенных в Азии, надо
набрать программу
Ее результатом будет
Проверяемые условия задаются знаками операций <,
<=, ==, !=,
>=, >. Если в выражении
сравнения оба операнда являются числами, выполняется
числовое сравнение; в противном случае операнды
сравниваются как цепочки символов. Так, шаблон
отбирает строки, начинающиеся с S, T,
U и т.д.; в нашем случае это
Если дополнительная информация о типе отсутствует, поля трактуются
как цепочки символов, поэтому программа
сравнивает первое и четвертое поля как цепочки символов и выводит
на печать единственную строку:
Кроме возможностей, проиллюстрированных в предыдущем разделе, в
awk'е есть и более мощное средство спецификации шаблонов -
регулярные выражения. Простейшим регулярным выражением является
буквальное указание требуемой цепочки. Пример (регулярные выражения
обрамляются символами /):
Данное регулярное выражение - законченная awk-программа,
печатающая все строки, содержащие какое-либо вхождение цепочки
Asia. Если строка содержит более длинное слово, частью которого
является цепочка Asia, например
Asiatic, она все равно печатается (в файле
countries, однако, таких слов нет).
Используемые в awk'е регулярные выражения трактуются так же,
как в распознавателе шаблонов egrep(1). Ряд символов
имеет специальный смысл.
Например, чтобы напечатать все строки, начинающиеся с A, следу-
ет указать регулярное выражение
Для печати всех строк, начинающихся с A,
B или C, годится регулярное выражение
Все строки, оканчивающиеся цепочкой ia, распечатываются
с помощью шаблона
В общем случае, символ ^ обозначает
начало строки, символ $ -
конец строки, а символы, заключенные в квадратные скобки, [],
сопоставляются с любым одиночным символом из перечисленных в
скобках. Кроме того, awk позволяет использовать круглые скобки
для группировки, а символ | - для перечисления альтернатив.
Знак + определяет, что предшествовавшее ему выражение должно
сопоставляться один или более раз, знак ? обозначает повторение
нуль или один раз. Программа
печатает все цепочки, содержащие x или y, программа
выводит все цепочки, содержащие символ a, за которым следует
один или более символов x,
а затем b (например, axb,
Paxxxxxxxb, QaxxbR). Программа
печатает все цепочки, содержащие символ a, за которым следует
необязательный x, а затем символ
b (например, ab, axb,
yaxbPPPP, CabD).
Два символа, . и *, имеют тот
же смысл, что и в ed(1). Более
подробно, . обозначает произвольный символ, а
* - нуль или более вхождений предыдущего символа. Так, шаблон
сопоставляется с любой записью, содержащей символ a, за которым
следует произвольный символ, а затем символ b. Другими словами,
запись должна включать символы a и
b, разделенные произвольным
символом. Например, /a.b/ сопоставляются с
axb, aPb и
xxxxaXbxx, но не с ab, axxb. Шаблон
сопоставляется с записью, содержащей символы a
и c, разделенные
цепочкой из произвольного, возможно нулевого, числа символов x.
Например, она сопоставляется с цепочками
Так же, как и в ed(1),
можно отменить специальную интерпретацию
метасимволов (например, ^ и *).
Для этого перед такими символами ставится знак \. Например, шаблон
сопоставляется с произвольной цепочкой символов, заключенной в
"скобки" /.../.
Можно также специфицировать, что некоторое поле (переменная)
должно сопоставляться с регулярным выражением (либо не
сопоставляться). Это делается при помощи операций ~
и !~. Например,
для входного файла countries следующая программа выводит на
печать все страны, названия которых заканчиваются цепочкой ia:
Шаблон может быть составлен из более простых шаблонов, объединенных
операциями || (ИЛИ),
&& (И), ! (ОТРИЦАНИЕ) и скобок.
Например, шаблон
отбирает строки, относящиеся к странам, как площадь,
так и население которых достаточно большие:
Шаблон
$4 == "Asia" || $4 == "Africa"
отбирает строки, четвертое поле в которых совпадает либо с
Asia, либо с Africa.
Альтернативный способ спецификации послед-
него шаблона:
Шаблон специфицирует отбор записей, четвертое поле в которых
сопоставляется с цепочкой Asia или Africa,
причем сопоставление
начинается с первого символа и заканчивается последним.
Операции && и ||
гарантирует, что их операнды обрабатываются
слева направо; обработка прекращается, как только установлено
истинностное значение выражения.
Шаблон в awk'е может также состоять из двух шаблонов,
разделенных запятой:
В этом случае действие выполняется для
каждой строки, начиная
со строки, удовлетворяющей шаблону1,
и заканчивая строкой,
удовлетворяющей шаблону2. Следующий оператор,
в котором отсутствует действие,
печатает все строки, расположенные между строкой, содержащей
цепочку Canada, и строкой, содержащей цепочку
Brazil. Например:
Шаблон
вызывает выполнение действия для входных строк со второй по
пятую. Разные типы шаблонов можно смешивать, например:
Данный оператор печатает все строки, начиная с той, которая содержит
цепочку Canada, и заканчивая той, четвертое поле которой
суть Africa.
Примечание
Действием в языке awk является последовательность операторов,
разделенных переводами строки или точками с запятой. Действия
позволяют решать множество задач, связанных с бухгалтерскими
расчетами и обработкой цепочек символов.
awk дает возможность выполнять арифметические вычисления и
сохранять их результаты в переменных для последующего использования.
В качестве примера рассмотрим вывод на печать плотности
населения тех стран, информация о которых содержится в файле
countries:
(Напомним, что в этом файле население страны указано в миллионах
человек, а площадь - в тысячах квадратных миль.) Результатом
является количество людей, приходящееся на одну квадратную
милю:
Формат у этой таблицы получился не очень красивым; если использовать
вместо print оператор printf:
результат будет таким:
Все промежуточные арифметические вычисления выполняются над вещественными
числами. Допускаются следующие арифметические операции: +,
-, *, /, %
(остаток от деления).
Чтобы вычислить суммарное население и число стран из Азии, можно
использовать программу
которая печатает:
Операции ++, --, +=, -=,
/=, *=, %= используются в
awk'е так же, как в языке C. Операция ++,
например, увеличивает значение переменной на единицу. Операции
++ и -- (как и в C) могут быть
и префиксными, и постфиксными. Все эти операции можно использовать
также и в выражениях.
В предыдущем примере переменные pop и n
не были инициализированы;
тем не менее, программа работала нормально. Это происходит
потому, что (по умолчанию) переменные инициализируются пустой
цепочкой, числовое значение которой равно 0. Данное соглашение
устраняет необходимость большинства инициализаций переменных в
секции BEGIN.
В следующей программе, определяющей страну с самым большим
населением, также может быть использована неявная инициализация:
Ее результат:
Поля в awk'е разделяют по существу все свойства переменных. Они
используются в арифметических и текстовых операциях, могут быть
инициализированы пустой цепочкой, им можно присвоить другое
значение. Например, можно разделить значение второго поля на
1000, чтобы получить площадь в миллионах квадратных миль:
вычислить значение поля, исходя из значений двух других:
присвоить полю новое значение - цепочку:
Последняя программа заменяет в одной из строк поле USA на
United States и печатает новое значение строки:
К полям можно обращаться посредством выражений; например, $NF
обозначает последнее поле, а $(NF-1) - второе от конца.
Отметим, что скобки в последнем примере необходимы, поскольку $NF-1
есть выражение, значение которого на 1 меньше значения последнего поля.
Чтобы сконкатенировать цепочки символов, надо написать их одну
за другой. Например, программа
печатает
При использовании в качестве входного файла countries, программа
напечатает
В конкатенациях можно указывать переменные, текстовые и числовые
выражения; числовые значения в данном случае трактуются как
текстовые.
Некоторые переменные в awk имеют специальное назначение. В этом
разделе приводится полный список таких переменных и описание их
использования:
1.3.4. Функции
exp (выражение)
int (выражение)
log (выражение)
sqrt (выражение)
getline
index (выражение1, выражение2)
length
length (выражение)
split (выражение, идентификатор, выражение2)
split (выражение, идентификатор)
sprintf (формат, выражение1, выражение2 ...)
substr (выражение1, выражение2)
substr (выражение1, выражение2, выражение3)
index ("abc", "bc") = 2
index ("abc", "ac") = 0
length ("abc") = 3
length (17) = 2
n = split ($0, a)
substr ("abc", 2, 1) = "b"
substr ("abc", 2, 2) = "bc"
substr ("abc", 2, 3) = "bc"
1.4. Термы
первичное_выражение
терм биноп терм
уноп терм
переменная_с_приращением
( терм )
1.4.1. Бинарные термы
терм биноп терм
1.4.2. Унарные термы
В терме вида
уноп терм
1.4.3. Переменные с приращением
++пер
--пер
пер++
пер--
1.4.4. Термы, заключенные в скобки
1.5. Выражения
терм
терм терм ...
пер присвоп выражение
1.5.1. Конкатенация термов
1+2 3+4
1.5.2. Выражения-присваивания
пер присвоп выражение
=
+=
-=
*=
/=
%=
пер = выражение
пер оп= выражение
пер = пер оп выражение
b = b * (c-2)
a = a + b
2. ПРИМЕНЕНИЕ AWK'А
3. ВВОД/ВЫВОД
3.1. Запуск программ на выполнение
awk 'программа' [имя_файла...]
/x/ { print }
awk '/x/ { print }' file1
awk 'программа' файл1 -
awk -f имя_программы [имя_файла ...]
awk 'BEGIN { print "hello, world"; exit }'
hello, world
BEGIN { print "hello, world"; exit }
awk -f awkprog
3.2. Ввод: записи и поля
3.3. Ввод из файла
Russia 8650 262 Asia
Canada 3852 24 North America
China 3692 866 Asia
USA 3615 219 North America
Brazil 3286 116 South America
Australia 2968 14 Australia
India 1269 637 Asia
Argentina 1072 26 South America
Sudan 968 19 Africa
Algeria 920 18 Africa
Russia 8650 262 Asia
{ print $0 }
$2 эквивалентно цепочке "8650"
$3 эквивалентно цепочке "262"
$4 эквивалентно цепочке "Asia"
$5 эквивалентно пустой цепочке
. . .
awk '{ print $4, $1, $3 }' countries
awk -F\t '{ print $4, $1, $3 }' countries
3.4. Ввод из командной строки
x=5
awk '{ print x }' x=5 -
awk '{ print x }' x=5 file1
awk -f awkprog RS=":" file1
awk -F: -f awkprog file1
3.5. Вывод на печать
{ print }
awk '{ print $1, $3 }' countries
Russia 262
Canada 24
China 866
USA 219
Brazil 116
Australia 14
India 637
Argentina 26
Sudan 19
Algeria 18
{ print $1 }
так и
{ print $1; }
{ x=5; print x }
{ print $3, $2 }
эквивалентно
{ print ($3, $2) }
{ print "hello, world " }
{ print NR, NF, $0 }
1 4 Russia 8650 262 Asia
2 5 Canada 3852 24 North America
3 4 China 3692 866 Asia
4 5 USA 3615 219 North America
5 5 Brazil 3286 116 South America
6 4 Australia 2968 14 Australia
7 4 India 1269 637 Asia
8 5 Argentina 1072 26 South America
9 4 Sudan 968 19 Africa
10 4 Algeria 920 18 Africa
{ print NR, $1 }
1 Russia
2 Canada
3 China
4 USA
5 Brazil
6 Australia
7 India
8 Argentina
9 Sudan
10 Algeria
{ print "" }
printf "формат", выражение, выражение, ...
{ printf "%10s %6d %6d\n", $1, $2, $3 }
Russia 8650 262
Canada 3852 24
China 3692 866
USA 3615 219
Brazil 3286 116
Australia 2968 14
India 1269 637
Argentina 1072 26
Sudan 968 19
Algeria 920 18
/x/
{ x="hello"; y="world"
print x, y
}
hello world
{ x="hello"; y="world"
print x y
}
helloworld
{ x="hello"; y="world"
print x"," y
}
BEGIN { OFS=", " }
{ x="hello"; y="world"
print x, y
}
hello, world
3.6. Вывод в различные файлы
{ if ($4 == "Asia") print > "ASIA"
if ($4 == "Europe") print > "EUROPE"
if ($4 == "North") print > "NORTH_AMERICA"
if ($4 == "South") print > "SOUTH_AMERICA"
if ($4 == "Australia") print > "AUSTRALIA"
if ($4 == "Africa") print > "AFRICA"
}
printf > "имя_файла"
3.7. Вывод в каналы
{
if ($2 == "XX") print | "mailx mary"
}
{
print $1 | "sort"
}
{
print ... | "cat -v > /dev/tty"
}
4. ШАБЛОНЫ
4.1. BEGIN и END
BEGIN {print "Country","Area","Population","Continent"}
{ print }
Country Area Population Continent
Russia 8650 262 Asia
Canada 3852 24 North America
China 3692 866 Asia
USA 3615 219 North America
Brazil 3286 116 South America
Australia 2968 14 Australia
India 1269 637 Asia
Argentina 1072 26 South America
Sudan 968 19 Africa
Algeria 920 18 Africa
BEGIN { FS= "\t"
printf "Country\t\t Area\tPopulation\tContinent\n\n"}
{ printf "%-10s\t%6d\t%6d\t\t% -14s\n", $1, $2, $3, $4 }
END { print "The number of records is", NR }
4.2. Выражения сравнения
$3 > 100
Russia 8650 262 Asia
China 3692 866 Asia
USA 3615 219 North America
Brazil 3286 116 South America
India 1269 637 Asia
$4 == "Asia" { print $1 }
Russia
China
India
$1 >= "S"
USA 3615 219 North America
Sudan 968 19 Africa
$1 == $4
Australia 2968 14 Australia
4.3. Регулярные выражения
/Asia/
/^A/
/^[ABC]/
/ia$/
/x|y/ { print }
/ax+b/ { print }
/ax?b/ { print }
/a.b/
/ax*c/
ac
axc
pqraxxxxxxxxxxc901
/\/.*\//
Russia
Australia
India
Algeria
4.4. Комбинации шаблонов
$2 >= 3000 && $3 >= 100
Russia 8650 262 Asia
China 3692 866 Asia
USA 3615 219 North America
Brazil 3286 116 South America
$4 ~ /^(Asia|Africa)$/
4.5. Шаблоны-диапазоны
шаблон1, шаблон2 { действие }
/Canada/,/Brazil/
Canada 3852 24 North America
China 3692 866 Asia
USA 3615 219 North America
Brazil 3286 116 South America
NR == 2, NR == 5 { ... }
/Canada/, $4 == "Africa"
5. ДЕЙСТВИЯ
5.1. Переменные, выражения и присваивания
{ print $1 (1000000 * $3) / ($2 * 1000) }
Russia 30.289
Canada 6.23053
China 234.561
USA 60.5809
Brazil 35.3013
Australia 4.71698
India 501.97
Argentina 24.2537
Sudan 19.6281
Algeria 19.5652
{ printf "%10s %6.1f\n", $1, (1000000*$3)/($2*1000) }
Russia 30.3
Canada 6.2
China 234.6
USA 60.6
Brazil 35.3
Australia 4.7
India 502.0
Argentina 24.3
Sudan 19.6
Algeria 19.6
/Asia/ { pop += $3; ++n }
END { print "total population of", n,
"Asian countries is", pop }
total population of 3 Asian countries is 1765
5.2. Инициализация переменных
maxpop < $3 {
maxpop = $3
country = $1
}
END { print country, maxpop }
CHINA 866
5.3. Переменные-поля
{ $2 /= 1000; print }
BEGIN { FS = "\t" }
{ $4 = 1000 * $3 / $2; print }
/USA/ { $1 = "United States" ; print }
United States 3615 219 North America
5.4. Конкатенация цепочек
{ x = "hello"
x = x", world"
print x
}
hello, world
/^A/ { s = s " " $1 }
END { print s }
Australia Argentina Algeria
5.5. Специальные переменные
| NR | |
| Порядковый номер текущей записи. | |
| NF | |
| Число полей в текущей записи. | |
| FS | |
| Входной разделитель полей, по умолчанию равен пробелу/табуляции. | |
| RS | |
| Входной разделитель записей, по умолчанию равен символу перевода строки. | |
| $i | |
| i-е поле текущей записи. | |
| $0 | |
| Текущая входная запись целиком. | |
| OFS | |
| Выходной разделитель полей, по умолчанию равен пробелу. | |
| ORS | |
| Выходной разделитель записей, по умолчанию равен символу перевода строки. | |
| OFMT | |
| Формат для вывода на печать чисел, используется оператором print; по умолчанию равен %.6g. | |
| FILENAME | |
| Имя файла, из которого в данный момент производится ввод. Это удобно, поскольку обычно awk-программы имеют вид |
awk -f программа файл1 файл2 файл3 ...
Переменные (и поля) принимают числовые или текстовые значения в зависимости от контекста. Например, в присваивании
pop += $3
pop полагается числом, в то время как в присваивании
country = $1
country - это цепочка символов. В выражении
maxpop < $3
тип maxpop зависит от данных, которые содержатся в $3, что определяется во время выполнения программы.
В общем случае, каждая переменная (поле) является потенциально цепочкой символов или числом, либо одновременно и тем и другим. Если значение переменной устанавливается присваиванием
пер = выражение
то ее тип становится равным типу выражения. ("Присваивание" - это также и +=, ++, -= и т.д.) Арифметическое выражение имеет тип число; конкатенация цепочек имеет тип цепочка_символов.
В сравнениях, если оба операнда являются числами, они и сравниваются как числа. В противном случае, операнды, если требуется, преобразуются в цепочки символов и выполняется сравнение этих цепочек.
Следующие трюки позволяют преобразовать тип любого выражения:
выражение + 0
трактуется как число, а
выражение ""
- как цепочка символов. (Последнее выражение - это конкатенация
с пустой цепочкой.)
Кроме обыкновенных переменных, awk предоставляет одномерные
массивы. Массивы не описываются явным образом, их элементы возникают,
когда на них ссылаются. Индекс может быть произвольной
непустой цепочкой, в том числе и не имеющей числового значения.
Как пример использования обычного числового индекса, оператор
присваивает текущую входную строку NR-му
элементу массива x. В
принципе, если выполнить следующую awk-программу:
можно в произвольном порядке обрабатывать все исходные данные
целиком (хотя, быть может, и довольно медленно). Первая строка
этой программы заносит входные записи в массив x.
Программа
(в случае обработки файла countries) порождает
массив со следующим содержимым:
Использование в качестве индексов в массиве нечисловых значений
придает awk'у возможности, сходные с возможностями
ассоциативной памяти Снобол-таблиц. Например, можно написать программу
которая порождает результат
Отметим, что индексные выражения можно конкатенировать. Кроме
того, в качестве индекса при обращении к массиву можно использовать
произвольное выражение. Так, в конструкции
текстовое значение первого поля строки используется как индекс
в массиве area.
В этом, заключительном разделе описывается использование
некоторых специфических возможностей awk'а.
Предоставляемая awk'ом функция length
позволяет вычислить длину
цепочки символов. Следующая программа печатает длину и
содержимое каждой записи:
В данном случае length эквивалентно
length($0), что обозначает
длину текущей записи. В общем случае, length (x) возвращает
длину аргумента x, трактуемого как цепочка символов.
При использовании countries в качестве входного файла,
следующая программа напечатает самое длинное название страны:
Функция split в форме
присваивает поля цепочки s последовательным элементам массива
array. Например, обращение
Данный вызов разбивает цепочку s на поля и помещает их в
array[1], ..., array[n].
Результат, возвращаемый split, равен числу
обнаруженных полей. Если аргумент sep указан, задаваемая им
цепочка используется в качестве разделителя полей; в противном
случае используется FS. Это бывает удобно, если требуется
в середине awk-программы переопределить для одной
записи разделитель полей.
Кроме того, awk предоставляет математические функции
Это функции вычисления квадратного корня, натурального логарифма,
экспоненты и целой части числа. Последняя функция возвращает
максимальное целочисленное значение, не превосходящее значения
аргумента. Перечисленные функции заимствуются из математичекой
библиотеки языка C (awk-функции int
соответствует функция
floor библиотеки libm),
поэтому в случае ошибки они возвращают
такие же результаты, что и их аналоги из libm (см. Справочник
программиста).
Функция substr в форме
возвращает подцепочку цепочки s,
начинающуюся с позиции m и
содержащую не более n символов. Если третий аргумент (в данном
случае - n) отсутствует, выделяется
подцепочка до конца s. Например, программа
позволяет сократить названия стран в файле countries:
Если s - число, substr
использует его текстовое представление:
Функция
возвращает номер начальной позиции первого вхождения цепочки s2
в цепочку s1, либо нуль,
если цепочка s2 не входит в цепочку s1.
Функция sprintf форматирует выражения так же, как это делает
оператор printf, однако не отправляет результат на стандартный
вывод, а присваивает его некоторой переменной. Например, оператор
присваивает переменной x цепочку символов, полученную форматным
преобразованием значений $1 и $2,
после чего x можно использовать в последующих вычислениях.
Функция getline немедленно читает следующую входную запись.
Значения полей, переменных $0 и
NR переустанавливаются, однако
управление остается в том же самом месте awk-программы.
getline возвращает 0, если обнаружен конец файла,
и 1, если считана обычная запись.
awk позволяет использовать в действиях следующие управляющие
конструкции:
и составной оператор, такой же, как в языке C.
Оператор if имеет следующий вид:
Условие вычисляется; если оно истинно, выполняется
оператор1; в
противном случае выполняется оператор2.
Часть else является необязательной. Несколько
операторов, заключенных в фигурные
скобки, трактуются как единый оператор. В примере, приведенном
в разделе Инициализация переменных, вычисление максимума населения
можно перенести из шаблона в действие, если воспользоваться
оператором if:
Оператор while имеет вид:
Условие вычисляется; если оно истинно,
выполняется оператор.
Условие вычисляется снова, и если оно истинно,
опять выполняется оператор. Цикл повторяется до тех
пор, пока условие истинно.
Например, следующая программа распечатывает все входные поля,
по одному на каждой строке:
Другой пример - алгоритм Евклида нахождения наибольшего общего
делителя $1 и $2:
Оператор for, аналогичный соответствующей конструкции языка C,
имеет вид
Так,
- это еще одна awk-программа, распечатывающая все входные поля,
по одному на каждой строке.
Имеется альтернативная форма оператора for, удобная для доступа
к элементам ассоциативного массива в awk:
Такая конструкция задает выполнение оператора
для i, принимающего последовательно каждое значение индекса
в массиве. Перебираются все индексы, однако порядок
перебора не определен. Хаос
гарантируется, если в теле цикла изменяется переменная i или
создаются новые элементы массива. Цикл for в такой форме можно
использовать, например, чтобы после завершения основной части
программы напечатать все входные записи, предварив их порядковыми номерами:
Более содержательным является следующий пример - индексы-цепочки
используются для вычисления суммарного населения стран по
континентам:
В данной программе тело цикла for выполняется для
i, равного по
очереди различным названиям континентов, до тех пор, пока все
возможные значения i не будут исчерпаны (то есть пока все
цепочки-названия не будут использованы). Отметим, однако, что порядок
вычислений не определен. Например, такая программа может
напечатать:
Отметим, что условие в операторах if, while
и for может включать:
Оператор break (если он встречается внутри циклов
while или for) приводит к немедленному
выходу из цикла.
Оператор continue (если он встречается внутри циклов
while или
for) приводит к началу следующей итерации цикла.
Встретившийся в awk-программе оператор
next заставляет awk немедленно
перейти к следующей записи и возобновить просмотр шаблонов
с начала программы. (Отметим различие между getline и
next: getline не
ведет к переходу к началу awk-программы.)
Если оператор exit встречается в секции
BEGIN awk-программы,
программа прекращает свое выполнение и выполняется секция END
(если она есть).
Если оператор exit встречается
в основной секции awk-программы,
прекращается выполнение основной секции. Последующие записи не
читаются, выполняется секция END.
Оператор exit в секции END
приводит к завершению выполнения
программы.
Использование управляющих конструкций в секции END особенно
удобно, если awk применяется в качестве средства генерации
отчетов. awk позволяет составлять сводки, форматировать
информацию, объединять ее в таблицы. В предыдущем разделе приводился
пример формирования таблицы населения. В этом разделе предлагается
еще один пример. Предположим, имеется файл prog.usage, содержащий
строки, каждая из которых состоит из трех полей: имя,
программа и число использований:
Например, первая строка означает, что Смит использует программу
draw три раза. Если надо определить общее число использований
каждой программы и упорядочить выходную информацию по алфавиту,
можно воспользоваться следующим awk-текстом (допустим, он
помещен в файл с именем list1):
Если использовать в качестве входного файл prog.usage, данная
программа сформирует следующий результат:
Если желательно отформатировать этот результат таким образом,
чтобы каждое имя печаталось только один раз, можно организовать
конвейер из предыдущей awk-программы и следующей программы
(которая помещена в файл с именем format1):
Переменная prev используется для того, чтобы убедиться, что
каждое уникальное значение $1 печатается ровно один раз. Команда
выдаст такой результат:
Часто оказывается удобным объединить несколько разных
awk-программ с другими командами shell'а, такими как
sort(1), что и было сделано в программе list1.
Обычно awk-программа либо помещается в файл, либо указывается в
командной строке (при этом ее текст заключается в одинарные кавычки):
Использование одинарных кавычек позволяет избежать интерпретации
shell'ом текста awk-программы. Это необходимо, потому что
многие специальные символы awk'а совпадают со специальными сим-
волами shell'а (например, $ или ").
Предположим, требуется написать awk-программу, печатающую
n-ое
поле записи, где n - параметр, задаваемый во время запуска
программы. Более подробно, мы хотим написать программу с именем
field, которая по запросу
выполняла бы команду
Как передать значение n в awk-программу?
Это можно сделать несколькими способами. Во-первых, можно поместить
в файл field строку
В данном случае существенно отсутствие пробелов: эта запись
воспринимается как единый аргумент, несмотря на то, что указаны
две пары кавычек. $1 находится вне кавычек, доступен shell'у и,
следовательно, должным образом подставится в текст программы
при выполнении shell-процедуры field.
Еще один способ решения задачи основывается на том, что shell
интерпретирует $-параметры, которые содержатся в
цепочках, заключенных в двойные кавычки:
Небольшая хитрость состоит в экранировании первого символа $ с
помощью \; $1, как
и в предыдущем случае, заменяется при обращении к
field на требуемое число.
Формируя специального вида индексы, можно смоделировать многомерные
массивы. Например, в действии
создается массив, индексы в котором имеют вид i,j, то есть 1,1,
1,2 и так далее; тем самым моделируется двумерный массив.
5.7. Массивы
x [NR] = $0
{ x [NR] = $0 }
END { ... программа ... }
{ x [NR] = $1 }
x [1] = "Russia"
x [2] = "Canada"
x [3] = "China"
. . .
/Asia/ { pop ["Asia"] += $3 }
/Africa/ { pop ["Africa"] += $3 }
END { print "Asia=" pop ["Asia"] ,
"Africa=" pop ["Africa"] }
Asia=1765 Africa=37
area [$1] = $2
6. СПЕЦИФИЧЕСКИЕ ВОЗМОЖНОСТИ
6.1. Встроенные функции
{ print length, $0 }
length ($1) > max { max = length ($1); name = $1 }
END { print name }
split (s, array)
split ("Now is the time", w)
присваивает значение Now элементу w[1],
is - w[2], the - w[3],
time - w[4]. Все другие элементы
массива w[] устанавливаются
равными пустой цепочке. Можно указать, что роль разделителя полей
должен играть не пробел, а другой символ. В таком случае
используется иная форма функции split, с тремя аргументами:
n = split (s, array, sep)
sqrt
log
exp
int
substr (s, m, n)
{ $1 = substr ($1, 1, 3); print }
Rus 8650 262 Asia
Can 3852 24 North America
Chi 3692 866 Asia
USA 3615 219 North America
Bra 3286 116 South America
Aus 2968 14 Australia
Ind 1269 637 Asia
Arg 1072 26 South America
Sud 968 19 Africa
Alg 920 18 Africa
substr (123456789, 3, 4) = 3456
index (s1, s2)
x = sprintf ("%10s %6d", $1, $2)
6.2. Управляющие конструкции
if-else
while
for
if ( условие ) оператор1 else оператор2
{ if (maxpop < $3) {
maxpop = $3
country = $1
}
}
END { print country, maxpop }
while ( условие ) оператор
{ i = 1
while (i <= NF) {
print $i
++i
}
}
{ printf "the greatest common divisor of "
$1 "and ", $2, "is"
while ($1 != $2) {
if ($1 > $2) $1 -= $2
else $2 -= $1
}
printf $1 "\n"
}
for ( выражение1 ; условие ; выражение2 ) оператор
{ for (i = 1 ; i <= NF; i++)
print $i
}
for ( i in массив ) оператор
{ x [NR] = $0 }
END { for (i in x) print i, x [i] }
BEGIN { FS="\t" }
{ population [$4] += $3 }
END { for (i in population)
print i, population [i]
}
Africa 37
South America 142
Asia 1765
North America 243
Australia 14
6.3. Генерация отчетов
Smith draw 3
Brown eqn 1
Jones nroff 4
Smith nroff 1
Jones spell 5
Brown spell 9
Smith draw 6
{ use [$1 " " $2] += $3 }
END { for (np in use)
print np "\t" use [np] | "sort +0 +2nr"
}
Brown eqn 1
Brown spell 9
Jones nroff 4
Jones spell 5
Smith draw 9
Smith nroff 1
{ if ($1 != prev) {
print $1 ":"
prev = $1
}
print "\t" $2 "\t" $3
}
awk -f list1 prog.usage | awk -f format1
Brown:
eqn 1
spell 9
Jones:
nroff 4
spell 5
Smith:
draw 9
nroff 1
6.4. Взаимодействие с shell'ом
awk '{ print $1 }' ...
field n
awk '{ print $n }'
awk '{ print $'$1' }'
awk "{ print \$ $1 }"
6.5. Многомерные массивы
for (i = 1; i <= 10; i++)
for (j = 1; j <= 10; j++)
mult [i ',' j] = ...
| Назад | Оглавление | Вперед |
| Каталог | Индекс раздела |