ЗАНЯТИЕ N3

 

Цель занятия

 

Изучить потоковый редактор awk и используемый в нем диалект регулярных выражений.

 

Порядок проведения занятия

 

1. Прочитать приведенную ниже краткую информацию о редакторе awk и методические материалы по использованию редактора awk, находящиеся по адресу:

http://cs.ifmo.ru/education/documentation/awk

http://cs.ifmo.ru/education/documentation/sed_awk

2. Выполнить упражнения с готовыми примерами использования команд редактора awk, объяснить результаты их выполнения и ответить на вопросы преподавателя.

3. Выполнить задания на самостоятельную работу с использованием утилиты nawk - лабораторная работа N3. Оформить отчет и защитить его в начале следующего занятия, ответив на контрольные вопросы преподавателя.

 

Краткая информация о редакторе awk

 

Семейство утилит awk это потоковые редакторы, имеющие свой собственный язык программирования. Само название составлено из инициалов авторов: Alfred Aho, Brian Kernighan и Peter Weinberger. Nawk это более новая версия редактора, а gawk версия редактора в GNU исполнении для Linux.

 

Все версии утилит awk могут получать данные для обработки из одного или более файлов. Если файлы не указаны, то входные данные берутся со стандартного устройства ввода (stdin) с клавиатуры, или из программного канала конвейера. Программы, написанные на awk, могут быть короткими и умещаться в командной строке, а могут размещаться в отдельных командных файлах, с необязательным указанием в первой строке на версию утилиты, необходимой для выполнения сценария, например: #!/usr/bin/nawk.

 

Допустимы следующие форматы командной строки:

 

nawk 'pattern' filename (или cmd | nawk 'pattern')

nawk '{action}' filename (или cmd | nawk '{action}')

nawk 'pattern {action}' filename (или cmd | nawk 'pattern {action}')

 

Для пояснения принципа работы утилиты awk использован файл employees следующего содержания:

 

% cat employees

Tom Jones             4424    5/12/66                543354

Mary Adams            5346    11/4/63                28765

Sally Chang           1654    7/22/54                650000

Billy Black           1683    9/23/44                336500

 

Команда nawk '/Mary/' employees выводит на экран все строки из файла employees, которые содержат последовательность символов Mary:

 

Mary Adams            5346    11/4/63                28765

 

Команда nawk '{print $1}' employees выводит на экран первое поле каждой строки файла employees.

 

Tom

Mary

Sally

Billy

 

Команда nawk '/Sally/{print $1, $2}' employees выводит на экран первое и второе поле строки файла employees, содержащей последовательность символов Sally. Поля разделены пробелом:

 

Sally Chang

 

Общий принцип работы утилиты awk следующий:

 

Awk получает на вход из файла или программного канала строку и помещает ее во внутреннюю переменную $0. Каждая помещаемая в переменную $0 строка называется в терминологии awk записью и заканчивается символом новой строки.

 

Затем строка разбивается на части, разделителями которых являются по умолчанию символы пробела или табуляции. Эти части строки помещаются во внутренние нумерованные переменные, начиная с $1, и называются полями записи.

 

При выводе с помощью функции print поля отделяются друг от друга пробелом, так как между $1 и $2 стоит запятая. Запятая указывает на необходимость использовать при выводе в качестве разделителя полей содержимое переменной OFS, значением по умолчанию которой является пробел. Функция print воспринимает в качестве аргумента переменные, вычисляемые значения и строковые константы. Последние должны быть заключены в двойные кавычки. Если запятая не используется, то значения будут выведены без разделителя, т.е. соединены друг с другом.

 

Действия, выполняемые командой awk, заключаются в фигурные скобки. Если никакие действия не указаны и шаблон поиска совпадает с текстом строки, то awk выполняет действие, предусмотренное по умолчанию выводит на экран соответствующие шаблону строки.

 

% date

Wed Jul 28 22:23:16 PDT 2004

%

% date | nawk '{print "Month: " $2 "\nYear: " $6}'

Month: Jul

Year: 2004

 

В приведенном выше примере вывод команды date будет направлен на вход утилиты nawk. Второе поле единственной записи будет напечатано после символов "Month: ", затем с новой строки (\n) после символов "Year: " будет напечатано шестое поле. Символ новой строки указан в виде мета последовательности \n. Он необходим только для организации многострочного вывода. Завершающий символ новой строки будет добавлен функцией print автоматически. Можно также указать символ табуляции - \t, возврата курсора - \r или использовать восьмеричный код символа, например: \047 одинарные кавычки (апостроф), и т.д. Если мета последовательность, начинающаяся с символа \, не имеет специального значения, то будет выведен символ, указанный после \, в том числе и символ \, если он был указан как \\.

 

Если при выводе информации необходимо точное форматирование, можно использовать функции printf и sprintf, действие которых аналогично функции printf() языка C. В отличие от функции print функции printf и sprintf не дополняют вывод символом новой строки, по этому его необходимо всегда явно указывать в виде мета последовательности \n.

 

При выводе числовых значений формат вывода можно контролировать с помощью переменной OFMT. По умолчанию ее значение равно "%.6g", что означает печатать шесть символов справа от десятичной точки. Значение этой переменной может быть изменено следующим образом.

 

% nawk  'BEGIN{OFMT="%.2f"; print 1.2456789, 12E 2}'

1.25  0.12

 

В данном примере формат вывода, присвоенный переменной OFMT, означает, что числа с плавающей точкой (f) будут выведены с точностью два знака после запятой.

 

Если программа на языке awk размещается в файле, то имя командного файла указывается в командной строке после ключа -f. Awk считывает строку данных во внутренний буфер и присваивает ее внутренней переменной $0, а ее поля - переменным $1, $2 и т.д. Затем каждая команда из командного файла применяется к находящейся в буфере записи. После того как все команды из командного файла будут выполнены, awk считывает следующую строку во внутренний буфер и, начиная с первой команды, снова выполняет весь командный файл.

 

% cat awkfile

/^Mary/{print "Hello Mary!"}

{print NR, $1, $2, $3}

 

% nawk f awkfile employees

1 Tom Jones 4424

Hello Mary!

2 Mary Adams 5346

3 Sally Chang 1654

4 Billy Black 1683

 

В приведенном выше примере в командном файле awkfile находятся две строки, содержащие действия. Если запись начинается с последовательности символов "Mary", то будет выполнено первое действие - выведена строка символов "Hello Mary!". Для второго действия условия его выполнения не задано, по этому оно будет выполнено для каждой строки обрабатываемого текста, т.е. для каждой записи через пробел будут напечатаны поля $1, $2 и $3. Во встроенной переменной NR в момент выполнения программы хранится номер обрабатываемой записи. По этому в начале каждой строки будет напечатан ее номер. Количество полей записи хранится в переменной NF.

 

Символы разделители полей содержатся во внутренней переменной FS, и могут быть заменены другими, такими как точка с запятой, двоеточие, тире и т.д. Переменную FS можно установить в секции BEGIN командного файла, или с помощью ключа -F в командной строке. Например, для работы с записями файла /etc/passwd в качестве разделителя полей необходимо установить символ двоеточия (:).

 

% nawk F: '/root/{print $1, $7}' /etc/passwd

root /bin/ksh

 

В качестве разделителей полей можно указывать несколько символов, использую для этого конструкцию, обозначающую класс символов - [].

 

% nawk F[:/] '/root/{print $1, $9, $10}' /etc/passwd

root bin ksh

 

Если над каждой записью необходимо выполнить большую последовательность действий, то можно создать командный файл на языке утилиты awk. Если действия располагаются в одной строке, то они отделяются друг от друга символом точки с запятой (;). Если действие предваряется шаблоном поиска, то открывающая фигурная скобка блока действий, относящегося к данному шаблону, должна находится в той же строке, что и сам шаблон. Комментарии начинаются с символа #.

 

% cat info

# My first awk script

# Script name: info; Date: 27.11.2008

#

/Tom/{print  "Tom's birthday is "$4}

/Mary/{print NR, $0}

/^Sally/{print "Hi Sally. " $1, $2 " has a salary of  $" $5 "."}

 

% nawk f info employees

Tom's birthday is 5/12/66

2 Mary Adams            5346    11/4/63                28765

Hi Sally. Sally Chang has a salary of $65000.

 

Первые три строки файла info начинаются  с символа # и являются комментариями. Четвертая, пятая и шестая строки являются действиями, предваряемыми шаблоном поиска. Каждая пара шаблон-действие находится в отдельной строке, по этому использование символа точки с запятой (;) в качестве разделителя действий не обязательно.

 

 

Регулярные выражения в awk

 

Регулярное выражение в awk указывается между символами прямой наклонной черты (/), например: /Mary/. Набор метасимволов, используемых в awk, аналогичен утилите egrep:

^ якорный символ привязки регулярного выражения к началу строки

$ якорный символ привязки регулярного выражения к концу строки

. соответствует одному любому символу

* соответствует нулевому и более количеству повторений символа

+ соответствует одному и более количеству повторений символа

? соответствует одному или нулевому количеству повторений символа

[] соответствует одному из перечисленных в скобках символу

[^] соответствует одному из НЕ перечисленных в скобках символу

a|b соответствует либо a либо b

() группирующие скобки

& запоминает всю найденную строку

 

В awk НЕ поддерживаются следующие метасимволы:

\< якорный символ привязки регулярного выражения к началу слова

\> якорный символ привязки регулярного выражения к концу слова

\(\) запоминающие скобки

\{m,n\} интервал повторения символа

Регулярное выражение в awk может использоваться как в качестве шаблона поиска, применительно ко всей записи, так и в качестве шаблона поиска (соответствия) конкретного поля. Для этого может использоваться оператор совпадения, обозначаемый символом тильда (~). Например:

 

% nawk '$1 ~ /[Bb]ill/' employees

Billy Black           1683    9/23/44                336500

 

В данном примере будут выведены полностью все записи, содержащие в первом поле последовательности символов Bill или bill.

 

В GNU версиях gawk добавлена поддержка POSIX классов, имеющих следующие обозначения:

 

[:alnum:]   - алфавитные символы и цифры

[:alpha:]   - алфавитные символы

[:blank:]   - пробел и табуляция

[:cntrl:]   - управляющие символы

[:digit:]   - цифры

[:graph:]   - отображаемые символы (не пробелы, не управляющие символы и т.д.)

[:lower:]   - алфавитные символы нижнего регистра

[:print:]   - аналог [:graph:], но включает пробел

[:punct:]   - знаки препинания

[:space:]   - все пропуски ([:blank:], символ новой строки, возврат курсора и т.д.)

[:upper:]   - алфавитные символы верхнего регистра

[:xdigit:]  - цифры, допустимые в шестнадцатеричных числах (то есть 0-9a-fA-F)

 

Запись [:alnum:] эквивалентна записи A-Za-z0-9. Для использования ее в составе классов регулярных выражений необходимы вторые квадратные скобки, например:

 

% gawk '/[[:lower:]]+g[[:space:]]+[[:digit:]]/' employees

Sally Chang 1654 7/22/54 650000

 

В операционных системах Linux awk является ссылкой на утилиту gawk.

 

 

Упражнения на использование утилиты awk

 

В примерах используются файлы с данными, находящимися в каталоге /home/ad/re1 на сервере helios.

 

nawk '/west/'  datafile

nawk '/^north/' datafile

nawk '/^(no|so)/' datafile

nawk '{print $3, $2}' datafile

nawk '{print $3 $2}' datafile

nawk '{print $0}' datafile

nawk '{print "Number of fields: "NF}' datafile

nawk '/northeast/{print $3, $2}' datafile

nawk '/E/' datafile

nawk '/^[ns]/{print $1}' datafile

nawk '$5 ~ /\.[7-9]+/' datafile

nawk '$2 !~ /E/{print $1, $2}' datafile

nawk '$3 ~ /^Joel/{print $3 " is a nice guy."}' datafile

nawk '$8 ~ /[0-9][0-9]$/{print $8}' datafile

nawk '$4 ~ /Chin$/{print "The price is $" $8 "."}' datafile

nawk '/TJ/{print $0}' datafile

 
 

Лабораторная работа №3

 

Задания для самостоятельной работы ориентированы на использование файла данных /home/ad/re1/database. Файл database содержит записи, включающие в себя имена и фамилии сотрудников, их номера телефонов и денежные вклады в компанию за последние три месяца.

 

% cat /home/ad/re1/database

Mike Harrington:(510) 548-1278:250:100:175

Christian Dobbins:(408) 538-2358:155:90:201

Susan Dalsass:(206) 654-6279:250:60:50

Archie McNichol:(206) 548-1348:250:100:175

Jody Savage:(206) 548-1278:15:188:150

Guy Quigley:(916) 343-6410:250:100:175

Dan Savage:(406) 298-7744:450:300:275

Nancy McNeil:(206) 548-1278:250:80:75

John Goldenrod:(916) 348-4278:250:100:175

Chet Main:(510) 548-5258:50:95:135

Tom Savage:(408) 926-3456:250:168:200

Elizabeth Stachelin:(916) 440-1763:175:75:300

 

Задания на лабораторную работу:

 

1. Выведите все номера телефонов.

2. Выведите номер телефона, принадлежащий сотрудника Dan.

3. Выведите имя, фамилию и номер телефона сотрудницы Susan.

4. Выведите все фамилии, начинающиеся с буквы D.

5. Выведите все имена, начинающиеся с буквы C или E.

6. Выведите все имена, состоящие только из четырех букв.

7. Выведите имена сотрудников, префикс номера телефона которых 916.

8. Выведите денежные вклады сотрудника Mike, предваряя каждую сумму знаком $.

9. Выведите инициалы всех сотрудников.

10. Создайте командный файл awk, который:

Печатает полные имена и номера телефонов всех сотрудников по фамилии Savage.

Печатает денежные вклады сотрудника по имени Chet.

Печатает сотрдников, денежные вклады которых в первом месяце составили 250$.