355 500 произведений, 25 200 авторов.

Электронная библиотека книг » Дэвид Тейнсли » Linux и UNIX: программирование в shell. Руководство разработчика » Текст книги (страница 7)
Linux и UNIX: программирование в shell. Руководство разработчика
  • Текст добавлен: 15 октября 2016, 00:39

Текст книги "Linux и UNIX: программирование в shell. Руководство разработчика"


Автор книги: Дэвид Тейнсли



сообщить о нарушении

Текущая страница: 7 (всего у книги 25 страниц)

Таблица 9.3. Встроенные переменные awk

Переменная

Что содержит

ARGC

Количество аргументов в командной строке (поддерживается только: в nawk и gawk)

ARGV

Массив аргументов командной строки (поддерживается только в nawk и gawk)

ENVIRON

Массив переменных среды (поддерживается только в nawk и gawk)

FILENAME

Имя файла, обрабатываемого в текущий момент

FNR

Количество уже обработанных записей в текущем файле (поддерживается только в nawk и gawk)

FS

Разделитель полей во входном потоке (по умолчанию пробел); аналогична опции -F командной строки

NF

Количество полей в текущей записи

NR

Количество обработанных записей во входном потоке

OFS

Разделитель полей в выходном потоке (по умолчанию пробел)

ORS

Разделитель записей в выходном потоке (по умолчанию символ новой строки)

RS

Разделитель записей во входном потоке (по умолчанию символ

новой строки)

Переменная ARGC хранит число аргументов командной строки, переданной сценарию awk (точнее, nawk или gawk, т. к. эта переменная появилась только в новых версиях утилиты). Переменная argv хранит значения аргументов командной строки. Доступ к нужному аргументу осуществляется с помощью ссылки ARGV[n], где п – порядковый номер аргумента в командной строке.

Переменная environ хранит значения всех текущих переменных среды. Чтобы получить доступ к нужной переменной, следует указать ее имя, например:

ENVIRON["EDITOR"]=="vi"

Поскольку сценарий awk может обрабатывать большое количество файлов, предусмотрена переменная FILENAME, которая указывает на то, какой файл просматривается в текущий момент.

Переменная fnr хранит номер записи, которую утилита awk обрабатывает в текущий момент; ее значение меньше или равно значению переменной NR, которая отслеживает общее число обработанных записей входного потока. Если сценарий получает доступ более чем к одному файлу, переменная FNR сбрасывается в ноль при открытии каждого нового файла. В переменную NF записывается количество полей текущей записи. Ее значение сбрасывается по достижении конца записи.

Переменная FS содержит символ, используемый в качестве разделителя полей входного потока. Эту переменную можно установить из командной строки с помощью опиии -F. По умолчанию разделителем полей служит пробел. Переменная ofs содержит символ, являющийся разделителем полей в выходном потоке. По умолчанию это тоже пробел.

В переменной ORS хранится разделитель записей в выходном потоке. По умолчанию им является символ новой строки (n). Переменная RS содержит разделитель записей во входном потоке (в большинстве случаев это тоже символ n).

Переменные NF, NR и FILENAME

Представленная ниже команда позволяет быстро определить число записей во входном файле grade.txt. Значение переменной NR отображается по завершении обработки файла.

$ awk 'END {print NR}' grade.txt

В следующем примере на экран выводятся все записи исходного файла. Каждой из них предшествуют два числа: количество полей в записи (переменная NF) и номер записи в файле (переменная nr). В самом конце отображается имя входного файла (переменная FILENAME).

$ awk '{print NF, NR, $0} END {print FILENAME}' grade.txt

1

M. Tansley

05/99

48311

Green

8

40

44

2

J. Lulu

06/99

48317

green

9

24

26

3

P. Bunny

02/99

48

Yellow

12

35

28

4

J. Troll

07/99

4842

Brown-3

12

26

26

5

L. Tansley

05/99,

4712

Brown-2

12

30

28

grade.txt

Переменную NF удобно использовать, когда требуется извлечь из путевого имени последнюю часть, т. е. имя файла или каталога. В этом случае необходимо указать, что разделителем полей является символ '/' и использовать ссылку $NF, которая является обозначением последнего поля текущей записи. Например:

$ pwd

/usr/local/etc

$ echo $PWD | awk -F/ '{print $NF}'

Переменная среды $PWD хранит путевое имя текущего каталога.

9.2.10. Встроенные функции работы со строками

Утилита awk располагает набором универсальных функций преобразования строк. В табл. 9.4 перечислены основные из них.

Таблица 9.4. Функции работы со строками

Функция

Назначение

gsub(r,.s)

Выполняет глобальную замену каждой строки, соответствующей регулярному выражению г, строкой s в пределах текущей записи; появилась в nawk

index(s, t)

Возвращает позицию первого вхождения подстроки t в строку s

length(s)

Возвращает длину строки s

match(s, r)

Проверяет, содержит ли строка s подстроку, соответствующую, регулярному выражению r; появилась в nawk

split(s, a,fs)

Разбивает строку s на элементы, разделенные символом fs, и помещает полученные элементы в массив а

sub(r, s)

Выполняет замену самой первой строки, соответствующей регулярному выражению r, строкой s в пределах текущей записи; появилась в nawk

substr(s, p[,n])

Возвращает подстроку строки s, начинающуюся с позиции p и имеющую длину n; если аргумент п не задан, концом подстроки считается символ (признак конца строки)

Функция gsub()

Благодаря функции gsub() вы сможете выполнить в текущей записи глобальную замену строк, соответствующих заданному регулярному выражению. Например, для изменения номера ученика с 4842 на 4899 введите такую команду:

$ awk 'gsub(4842,4899) {print $0}' grade.txt

J. Troll 07/99 4899 Brown-3 12 26 26

Функция index()

Чтобы узнать позицию первого вхождения подстроки t в строку s, воспользуйтесь функцией index (), только не забудьте взять ее аргументы в двойные кавычки, иначе они будут восприниматься как имена переменных среды. Например, следующая команда возвращает число, определяющее позицию подстроки "ny" в строке "Bunny":

$ awk 'BEGIN {print index("Bunny","ny")}' grade.txt

4

Функция length()

Функция length() возвращает длину переданного ей текстового аргумента. В показанном ниже примере производится поиск информации об ученике с номером 4842, а затем определяется длина имени ученика:

$ awk '$3=4842 {print length($1)" "$1}' grade.txt

7 J.Troll

Следующая команда демонстрирует применение утилиты awk для вычисления длины текстовой строки:

$ awk 'BEGIN {print length("A FEW GOOD MEN")}'

14

Функция match()

Функция match() позволяет проверить, содержит ли строка заданную подстроку. Последняя может быть представлена как литералом в двойных кавычках, так и регулярным выражением. Если поиск прошел успешно, возвращается число, определяющее позицию, с которой начинается вхождение подстроки в искомую строку. В случае неудачи возвращается ноль. Следующая команда проверяет, содержит ли имя ученика с номером 48317 символ 'u':

$ awk '$3=48317 {print match ($1, "u"), $1} ' grade.txt

4 J. Lulu

Функция split()

Функция split() преобразует переданную ей строку в массив и возвращает число элементов в полученном массиве. В следующем примере заданная строка разбивается на три элемента, которые помещаются в массив myarray. Разделителем элементов в данном случае является символ '#'.

$ awk 'BEGIN {print split("123#456#678", myarray,"#"))'

3

Массив myarray будет иметь такую структуру:

mуarray[1]="123" myarray[2]="4 56"

myarray[3]="678"

Функция sub()

Функция sub() применяется для поиска строки, соответствующей заданному шаблону, и ее замены при первом появлении. В этом состоит отличие данной функции от функции gsub(), которая находит все случаи вхождения подстроки в строку, производя соответствующее число замен. Приведенная ниже команда находит запись ученика J. Troll и меняет его рейтинг с 26 на 29 (поле 6), при этом значение поля 7 (тоже 26) остается неизменным:

$ awk '$1=="J. Troll" {sub(26,29,$0) )' grade.txt

J. Troll 07/99 4842 Brown-3 12 29 26

Функция substr()

Функция substr() возвращает указанную часть строки. Вам нужно задать позицию, с которой начинается вхождение подстроки в искомую строку, и длину подстроки. Рассмотрим пример:

$ awk '$1=="L. Tansley" {print substr($1,1,5))' grade.txt

L. Tan

Эта команда возвращает из строки "L. Tansley" подстроку, начинающуюся с первого символа и занимающую пять символов.

Если значение третьего аргумента значительно превышает реальную длину строки, функция substr () возвращает все символы строки, начиная с указанной позиции:

$ awk '$1=="L. Tansley" {print substr ($1,3, 99) ) ' grade.txt

Tansley

То же самое происходит, когда третий аргумент вообще не указан. Например, следующая команда формирует список фамилий учеников:

$ awk '{print substr($1,3)}' grade.txt

Tansley

Lulu

Bunny

Troll

Tansley

Передача строк из интерпретатора shell утилите awk

Очень часто утилита awk получает входные данные не из файла, а по каналу от других команд. Рассмотрим несколько примеров обработки строк, поступающих из канала.

В первом примере команда echo передает строку "Stand‑by" утилите awk, которая вычисляет ее длину:

$ echo "Stand‑by" | awk '{print length($0)}'

8

Во втором примере утилита awk получает строку с именем файла и возвращает имя файла без расширения:

$ echo "mydoc.txt" | awk '{print substr($STR,1,5)}'

mydoc

Следующая команда возвращает только расширение файла:

$ echo "mydoc.txt" | awk '{print substr($STR,7)}'

txt

9.2.11. Escape–последовательности

При работе со строками и регулярными выражениями нередки случаи включения в шаблон поиска непечатаемых символов (таких как символ новой строки либо табуляции) или же символов со специальным значением в утилите awk (любой из метасимволов). Такие символы создаются с помощью управляющих Escape–последовательностей, признаком которых является обратная косая черта в начале.

Например, шаблон поиска открывающей фигурной скобки выглядит так:

/|/

В табл. 9.5 перечислены Escape–последовательности, распознаваемые утилитой awk.

Таблица 9.5. Escape–последовательности утилиты awk

b

Возврат на одну позицию (забой)

f

Прокрутка страницы

n

Новая строка

r

Возврат каретки

t

Горизонтальная табуляция

ddd

Восьмеричный код символа

c

Любой другой специальный символ. Например, запись \ соответствует символу обратной косой черты

В следующей команде сначала отображается фраза «May Day», в которой слова разделены символом табуляции, а затем выводятся два символа новой строки, вследствие чего образуется пустая строка. Потом отображается слово «May», а за ним -cлово «Day», каждая буква которого представлена ASCII–кодом: 'D' – 104, 'а'– 141,'у'– 171.

$ awk BEGIN {print "MaytDaynnMay 104141171"}'

May Day

May Day

9.2.12. Команда printf

Во всех примерах, с которыми мы ознакомились, данные выводились на экран с помощью команды print без какого‑либо форматирования. В awk имеется намного более мощная команда printf, аналог одноименной функции языка С, позволяющая задавать правила форматирования выходных данных.

Базовый синтаксис команды таков:

printf "строка_формaтирования", аргументы

Строка форматирования может включать как литеральные символы, записываемые в выходной поток без изменения, так и спецификаторы форматирования (табл. 9.6), каждый из которых задает способ интерпретации соответствующего ему аргумента.

Таблица 9.6. Спецификаторы форматирования

%c

Символ ASCI I; если аргумент является строкой, выводится первый символ строки

%d, %i

Целое число

%e

Число с плавающей точкой в формате [-]d.dddddde[+-]dd

%E

Аналогичен спецификатору %e, но знак экспоненты представлен символом 'E', а не 'e'

%f

Число с плавающей точкой в формате [~}ddd.dddddd

%G

Тип преобразования будет %e или %f в зависимости от того, какой результат короче; вывод незначащих нулей подавляется Аналогичен спецификатору %g, но экспоненциальный формат будет представлен спецификатором %E, а не %e .

%o

Восьмеричное число без знака

%s

Строка символов

%x

Шестнадцатеричное число без знака (используются шестнадцатеричные

цифры а, b, с, d, e, f)

Аналогичен спецификатору %x, но используются шестнадцатеричные

цифры А, В, С, D, E, F

%%

Отображается символ '%', интерпретации аргумента не происходит

В состав спецификаторов форматирования могут входить различные модификаторы, определяющие дополнительные особенности форматирования (табл. 9.7). Модификатор помещается между символом '%' и управляющим символом.

Таблица 9.7. Дополнительные модификаторы

-

Аргумент выравнивается по левому краю поля вывода (по умолчанию принято правостороннее выравнивание)

пробел

Если аргумент является положительным числом, перед ним ставится

пробел, а если отрицательным – знак минус

+

Если аргумент является числом, ему всегда предшествует знак плюс,

даже если это положительное число

#

Выбирается альтернативная форма спецификатора:

%о – восьмеричному числу предшествует ведущий ноль;

%x – шестнадцатеричному числу предшествует запись 0x;

%x – шестнадцатеричному числу предшествует запись Оx;

%e, %E, %f – число всегда содержит десятичную точку;

%g, %G – вывод незначащих нулей не подавляется

0

Если длина поля вывода больше, чем число символов в представлении

аргумента, аргумент дополняется нулями, а не пробелами

ширина

Ширина поля вывода; если длина поля больше, чем число символов

в представлении аргумента, аргумент по умолчанию дополняется

пробелами

. точность

Точность представления аргумента:

%е, %е, %f – число символов после десятичной точки;

%g, %g – максимальное число значащих цифр;

%d, %o, %i, %u, %x, %X – минимальное число выводимых цифр;

% s – максимальное число выводимых символов

Преобразование символов

Чтобы узнать, ASCII–код какого символа равен 65, можно с помощью команды echo направить строку "65" утилите awk и затем передать ее в качестве аргумента команде printf со спецификатором %с. Команда printf выполнит преобразование автоматически:

$ echo "65" | awk '{printf "%cn", $0}'

A

Как видите, это символ 'A'. Обратите внимание на наличие в команде символа новой строки (n). Необходимость в нем объясняется тем, что команда printf по умолчанию не записывает этот символ в выходной поток. Если не указать Escape–последовательность n, сразу после буквы 'А' в той же строке будет отображено приглашение интерпретатора shell, что может смутить пользователя, работающего в данный момент за терминалом.

Конечно, код символа может быть указан непосредственно в команде printf:

$ awk 'BEGIN {printf "%cn", 65}'

A

Форматированный вывод

Предположим, необходимо отобразить имена учеников и их идентификаторы, причем имена должны быть выровнены по левому краю и размещаться в поле длиной 15 символов. В конце строки форматирования стоит символ новой строки (n(,

служащий для разделения записей. Выводимые данные будут размещаться в двух колонках:

$ awk '{printf "%-l5s %dn", $1, $3}' grade.txt

M. Tansley 48311

J. Lulu 48311

P. Bunny 4 8

J. Troll 4842

L. Tansley 4712

9.2.13. Передача переменных утилите awk

Переменные можно создавать не только в сценарии awk, но и непосредственно в командной строке. Формат вызова утилиты awk в этом случае таков:

awk 'сценарий' переменная=значение входной_файл

В следующем примере переменная AGE создается в командной строке и инициализируется значением 10. Показанная команда находит студентов, возраст которых не превышает 10 лет.

$ awk '{if($5 < AGE) print $0}' AGE=10 grade.txt

M. Tansley 05/99 48311 Green 8 40 44

J. Lulu 06/99 48317 green 9 24 26

Рассмотрим более сложный пример. Системная команда df отображает информацию о смонтированных файловых системах. Результаты ее работы по умолчанию имеют следующий формат:

Имя

Число блоков .

Занято блоков

Свободно блоков

Процент

Точка монтирования

файловой системы

занятых

блоков

Столбец

1

2

3

4

5

6

Чтобы узнать, в какой из имеющихся файловых систем объем свободного пространства ниже критической отметки, следует передать выходные данные команды df утилите awk и последовательно сравнить значения в четвертом столбце с пороговым значением. В следующей командной строке пороговое число задано в виде переменной TRIGGER, которая равна 56000:

$ df -k | awk '$4 ~ /^[0-9]/ {if($4 < TRIGGER) print $1"t"$4)' TR1GGER=56000

/dos 55808 /apps 51022

Опция – к команды df устанавливает размер блока равным 1 Кб (наиболее привычный для пользователя режим), так как в системе может быть задан другой размер блока. Проверка $4 ~ /^[0-9]/ позволяет отсечь заголовок отчета команды df, содержащий в четвертом столбце строку "Available".

Вот еще один пример. Команда who выводит сведения о пользователях, зарегистрировавшихся в системе. В первом столбце выходных данных этой команды отображаются регистрационные имена пользователей, а во втором – имена терминалов, к которым подключены эти пользователи. С помощью утилиты awk вы можете

отфильтровать результаты работы команды who и узнать к какому терминалу подключены: ,

$ who | awk '{if($1==user) print $1 " you are connected to " $2}' user=$LOGNAME

root you are connected to ttyp1

Здесь локальная переменная user инициализируется значением переменой среды $LOGNAME, которая хранит регистрационное имя текущего пользователя.

9.2.14. Файлы сценариев

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

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

$ awk 'tot+=$6; END {print "Club student total points; " tot}' grade.txt

Создадим на ее основе файл, который назовем student_tot.awk. Расширение awk является общепринятым соглашением относительно именования файлов сценариев awk. Вот текст этого файла:

#!/bin/awk -f

#Все строки комментариев должны начинаться с символа '#'.

#Имя файла: student_tot.awk

#Командная строка: student_tot.awk grade.txt

#Вычисление суммарного и среднего рейтинга учеников секции.

#Сначала выводим заголовок.

BEGIN {

print "Student Date Member Grade Age Points Max"

print "name joined number gained point available"

print "================================================================="

}

# Суммируем рейтинг учеников.

tot+=$6

# В завершение выводим суммарный и средний рейтинг.

END {

print "Club student total points: " tot print "Average club student points: " tot/NR }

В этом сценарии мы формируем заголовок отчета и вычисляем не только суммарный рейтинг, но и средний рейтинг учеников секции, который получается путем деления переменной tot на переменную NR, содержащую число записей во входном файле. Как видите, на языке awk можно писать полноценные программы, содержащие команды, комментарии, а также пустые строки и дополнительные пробелы, предназначенные для повышения удобочитаемости текста сценария.

Ключевым моментом сценария является первая строка, выглядящая как комментарий:

#!/bin/awk -f

На самом деле это своеобразная системная инструкция, указывающая, какая программа должна выполнять данный сценарий– Подобная инструкция должна быть первой строкой любого сценария. Общий ее формат таков:

#!/путь/программа [командная_строка]

Выражение #! называется "магической" последовательностью. Подразумевается, что, во–neрвых, система, в которой запускается, сценарий, распознает эту последовательность, а, во–вторых, указанная программа воспринимает символ '#' как признак комментария. Это справедливо в отношении всех современных интерпретаторов shell, а также программ perl, awk. и sed, для которых чаще всего создаются автономные сценарии.

Когда происходит запуск исполняемого файла, система проверяет, начинается ли он с "магической" последовательности. Если нет, значит, файл содержит машинные коды и выполняется непосредственно. Если же обнаружено выражение #!, то это файл сценария. В таком случае происходит следующее:

   1. Первая строка сценария заменяет собой командную строку, из нее удаляется "магическая" последовательность;

   2. Предыдущая командная строка передается новой командной строке в качестве аргумента.

В нашем случае это означает, что при запуске сценария вместо команды

$ student_tot.awk grade.txt

в действительности выполняется такая команда:

$ /bin/awk -f student_tot.awk grade.txt

Опция -f утилиты awk говорит о том, что выполняемые команды находятся в указанном вслед за ней файле.

После создания файл student_tot.awk необходимо сделать исполняемым с помощью команды

$ chmod u+x student_tot.awk

Вот результаты работы сценария:

$ student_tot.awk grade.txt

Student name

Date joined

Member number

Grade

Age

Points gained

Max

point available

M. Tansley

05/99

18311

Green

8

40

44

J. Lulu

06/99

48317

green

9

24

26

P. Bunny

02/99

48

Yellow

12

35

28

J. Troll

07/99

4842

Brown-3

12

26

26

L. Tansley

05/99

4712

Brown~2

12

30

28

Club student

total points: 155

Average Club

Student

points: 31

Использование переменной FS в сценариях awk

Если просматривается файл, в котором разделителем полей является символ, отличный от пробела, например '#' или ':', это легко учесть, указав в командной строке опцию ' -F:'

$ awk -F: '{print $0}' входной_файл

Аналогичную функцию выполняет переменная FS, которую можно установить непосредственно в сценарии. Следующий сценарий обрабатывает файл /etc/passwd, выводя на экран содержимое первого и пятого полей, включающих соответственно имя пользователя и описание роли пользователя в системе. Поля в этом файле разделены символом двоеточия, поэтому в процедурной части шаблона begin устанавливается переменная FS, значение которой заключается в двойные кавычки:

$ cat passwd.awk

#!/bin/awk -f

# Имя файла: student_tot.awk

# Командная строка: passwd.awk /etc/passwd

# Вывод содержимого первого и пятого полей файла паролей.

BEGIN {

FS=":" }

{print $1"t"$5}

Вот возможные результаты работы этого сценария:

$ passwd.awk /etc/passwd

root Special Admin login

xdm Restart xda Login

sysadm Regular Admin login

daemon Daemon Login for daemons needing permissions

Передача переменных сценариям awk

При передаче переменной сценарию awk формат командной строки таков:

awk файл_сценария переменная=значение входной_файл

Следующий небольшой сценарий сравнивает количество полей в каждой записи входного файла с заданным в командной строке значением. Текущее количество полей хранится в переменной NF. Сравниваемое значение передается сценарию в виде переменной МАХ.

$ cat fieldcheck.awk

#!/bin/awk -f

#Имя файла: fieldcheck.awk

#Командная строка: fieldcheck.awk MAX=n [FS=<разделитель>] имя_файла

#Проверка числа полей в записях файла.

{if(NF != МАХ)

print "line " NR " does not have " MAX " fields"}

При запуске этого сценария вместе с файлом /etc/passwd, содержащим семь полей, необходимо указать следующие параметры:

$ fieldcheck.awk МАХ=7 FS=":" /etc/passwd

Следующий сценарий выводит информацию об учениках, чей возраст ниже значения, заданного в командной строке:

$ cat age.awk

#!/bin/awk -f

# Имя файла: age.awk

# Командная строка: age.awk AGE=n grade.txt

# Вывод информации об учениках, чей возраст ниже заданного,

{if($5 < AGE) print $0}

$ age.awk AGE=10 grade.txt

M. Tansley 05/99 48311 Green В 4 0 4 4 J. Lulu 06/99 18317 green 9 24 26

9.2.15. Массивы

Изучая функцию split(), мы говорили о том, каким образом ее можно использовать для преобразования строки символов в массив. Повторим соответствующий пример:

$ awk 'BEGIN {print split("123#456#678", myarray, "#")}'

3

Функция split() возвращает число элементов созданного массива myarray. Внутренняя структура массива myarray в этом случае такова:

myarray[1]="123" myаrray[2]="456" myarray[3]="678"

При работе с массивами в awk не требуется заранее их объявлять. Не нужно также указывать количество элементов массива. Для доступа к массиву обычно применяется цикл for, синтаксис которого следующий:

for (элемент in массив) print массив[элемент]

В показанном ниже сценарии функция split() разбивает заданную строку на элементы и записывает их в массив myarray, а в цикле for содержимое массива выводится на экран:

$ cat arraytest.awk

#! /bin/awk -f

#Имя файла: arraytest.awk

#Командная строка: arraytest.awk /dev/null

#Вывод элементов массива.

BEGIN {

record="l23#456#789";

split(record, myarray, "#") } END {

for (i in myarray) print myarray[i]

}

Для запуска сценария в качестве входного файла следует указать устройство /dev/null. Если этого не сделать, утилита awk будет ожидать поступления данных с клавиатуры.

$ arraytest.awk /dev/null

123

789

Статические массивы

В предыдущем примере массив формировался динамически. Следующий пример является более сложным и демонстрирует, как создавать в сценарии статические массивы. Ниже показан входной файл grade_student.txt, включающий информацию об учениках нашей секции каратистов. Записи файла содержат два поля: первое – название пояса, которым владеет ученик, второе – категория ученика (взрослый, юниор). Разделителем полей служит символ '#'.

$ cat grade_student.txt

Vellow#Junior

Orange#Senior

Yellow#Junior

Purple#Junior

Brown-2#Junior

White#Senior

Drange#Senior

Red#Junior

Brown-2#Senior

Yellow#Senior

Red#Junior

Blue#Senior

Green#Senior

Purple#Junior

White#Junior .

Наша задача заключается в том, чтобы прочитать файл и получить следующие сведения:

   1. Сколько учеников имеют желтый, оранжевый и красный пояса?

   2. Сколько взрослых и детей посещают секцию? Рассмотрим такой сценарий:

$ cat belts.awk

#!/bin/awk -f

#Имя файла: belts.awk

#Командная строка: belts.awk grade_student.txt

#Подсчет числа учеников, имеющих желтый, оранжевый и красный пояса,

#а также количества взрослых и юных членов секции.

# Задание разделителя и создание массивов.

BEGIN (

FS="#"

# Создание массива, индексами которого являются

#названия поясов. belt["Yellow"] belt["Orange"] belt["Red"]

#Создание массива, индексами которого являются

#названия категорий учеников. student["Junior"]

student["Senior"]

}

#Если значение первого поля совпадает с индексом массива belt,

#содержимое соответствующего элемента массива увеличивается на единицу. {for(colour in belt)

{if ($1==colour)

belt[colour]++ ) }

# Если значение второго поля совпадает с индексом массива student,

# содержимое соответствующего элемента массива увеличивается на единицу, { for (senior_or_junior in student) { if ($2==senior_or_junior)

student [senior_or_junior] ++

) }

# Вывод полученных результатов

END {

for (colour in belt)

print "The club has", belt[colour], colour, "belts" for(senior_or_junior in student)

print "The club has", 'student[senior_or_junior], senior_or_junior, "students" }

В процедурной части шаблона begin в переменную FS записывается символ '#" -pазделитель полей во входном файле. Затем создаются два массива, belt и student, индексами которых являются соответственно названия поясов и названия категорий учеников. Оба массива остаются неинициализированными, их тип не определен.

В первом цикле for значение первого поля каждой записи входного файла сравнивается с названием индекса массива belt (индекс равен "Yellow", "Orange" или "Red"). Если обнаруживается совпадение, выполняется приращение элемента, хранящегося в массиве по этому индексу. Поскольку операция ++ (инкремент) определена для целочисленных значений, утилита awk считает, что массив целочисленный, и инициализирует его элементы значением 0.

Во втором цикле for значение второго поля сравнивается с названием индекса массива student (индекс равен "Junior" или "Senior"). Результат операции вычисляется так же, как и в первом цикле.

В процедурной части шаблона end осуществляется вывод итоговых результатов.

$ belts.awk grade_student.txt

The club has 2 Red belts

The club has 2 Orange belts

The club has 3 Yellow belts

The club has 7 Senior students

The club has 8 Junior students

9.3. Заключение

Язык программирования awk может показаться сложным для изучения, но если осваивать его на примерах употребления отдельных команд и небольших сценариев, то процесс обучения не будет слишком трудным. В данной главе мы изучили основы awk, не углубляясь в детали, но, тем не менее, получили необходимый минимум сведений, относящихся к этому языку. Утилита awk является важным инструментом shell–программирования, и чтобы применять ее, вам не обязательно быть экспертом по языку awk.

ГЛАВА 10

Работа с редактором sed

Редактор sed относится к текстовым редакторам потокового типа и не является интерактивной программой. Он предназначен для обработки текстовых данных, поступающих из файла или стандартного входного потока. Отличительной особенностью редактора sed является то, что он позволяет модифицировать файлы в фоновом режиме. Задача пользователя сводится к тому, чтобы задать последовательность команд редактирования, а всю остальную работу выполнит сам редактор. Кроме того, sed допускает внесение всех изменений за один проход, а это превращает его в достаточно эффективный и, что важнее всего, быстродействующий инструмент редактирования текста.

В этой главе рассматриваются следующие темы:

   • синтаксис команд sed;

   • поиск строк по номерам и с использованием регулярных выражений;

   • изменение входного текста и добавление текста в выходной поток;

   • примеры команд и сценариев sed.

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

Поскольку редактор sed не предназначен для работы в интерактивном режиме, текстовые строки, подлежащие изменению, отбираются либо по номерам, либо на основании соответствия регулярному выражению.

10.1. Чтение и обработка данных в sed

Общая схема работы редактора sed такова:

   1. Редактор последовательно извлекает строки текста из файла или стандартного входного потока и копирует их в буфер редактирования.

   2. Затем он считывает первую команду из командной строки или сценария, осуществляет поиск строки с указанным номером или строки, соответствующей шаблону, и применяет к ней эту команду.

   3. Второй пункт повторяется до тех пор, пока не будет исчерпан список команд.

10.2. Вызов редактора sed

Вызвать редактор sed можно тремя способами:

   1. Ввести набор команд sed в командной строке.

   2. Поместить набор команд sed в файл и передать его редактору sed в командной строке.

   3. Поместить набор команд sed в файл сценария и сделать его выполняемым. Если редактор sed вызывается для выполнения одиночных команд, формат

командной строки будет таким:

sed [опции] 'команды' входной_файл

Как и в awk, не забудьте заключить команды в одинарные кавычки, чтобы защитить от интерпретации находящиеся в них специальные символы.


    Ваша оценка произведения:

Популярные книги за неделю