Упражнение 4.8
Наша проверка программы prpages
подсказывает иную реализацию этой программы. Поэкспериментируйте, чтобы выяснить, какая из них выполняется быстрее.
Управление
При редактировании большого файла очень легко (судя по опыту) случайно создать копию соседнего слова, что практически никогда не происходит преднамеренно. Для устранения таких ошибок в семействе программ Writers Workbench (рабочий набор редактора) существует программа double
, отыскивающая пары идентичных соседних слов. Ниже показана реализация этой программы с помощью awk
:
$ cat double
awk '
FILENAME != prevfile { # new file
NR = 1 # reset line number
prevfile = FILENAME
}
NF > 0 {
if ($1 == lastword)
printf "double %s, file %s, line %d\n" ,$1, FILENAME, NR
for (i = 2; i <= NF; i++)
if ($i == $(i-1))
printf "double %s, file %s, line %d\n", $i, FILENAME, NR
if (NF > 0)
lastword = $NF
}' $*
*
$
Операция ++
означает автоувеличение операнда, а операция --
— его автоуменьшение.
Встроенная переменная FILENAME
хранит имя текущего входного файла. Поскольку в переменной NR
подсчитывается число строк с начала входного потока, мы изменяем ее значение всякий раз при изменении имени файла, чтобы точно указать строку с двойником.
Оператор if
— такой же, как в языке Си:
if (условие)
оператор1
else
оператор2
Если условие верно, то выполняется оператор1
; если оно ложно и если альтернативная часть присутствует, то выполняется оператор2
. Альтернативная часть не обязательна.
Цикл for
аналогичен таковому в языке Си, но отличается от цикла в языке shell
:
for (выражение1; условие; выражение2)
оператор
Цикл for
идентичен приведенному ниже оператору, который также допустим в программе awk
:
Выражение1 while (условие) {
оператор
выражение2
}
Например, конструкция
for (i=2; i <= NF; i++)
является циклом с i
, принимающим значения 2, 3 и т.д., включая число полей NF
.
Оператор break
вызывает немедленный выход из цикла while
или for
; оператор continue
инициирует переход к следующему шагу цикла (к условию в операторе while
или к выражению2
в операторе for
). Оператор next
вызывает чтение следующей входной строки и сопоставление ее с шаблонами с начала программы awk
, а оператор exit
— немедленный переход на действия, определенные в шаблоне END
.
Массивы
Как и в большинстве языков программирования, в awk
есть массивы. В качестве простого примера приведем программу awk
, в которой каждая входная строка заносится в отдельный элемент массива, индексируемого номером строки, а затем они печатаются в обратном порядке:
$ cat backwards
# backwards: print input in backward line order
awk ' { line[NR] = $0 }
END { for (i = NR; i > 0; i--) print line[i] } ' $*
$
Заметьте, что подобно переменным, массивы не нужно описывать; размер массива ограничен только объемом памяти, доступным на вашей машине. Конечно, если очень большой файл заносится в массив, в конце концов, это может привести к исчерпанию ресурсов памяти. Для печати конца большого файла в обратном порядке следует обратиться за помощью к команде tail
:
$ tail -5 /usr/dict/web2 | backwards
zymurgy
zymotically
zymotic
zymosthenic
zymosis
$
Команда tail
использует возможности файловой системы — операцию "поиск" (seeking), позволяющую перейти к концу файла без чтения всей предшествующей информации. Подробнее эта операция будет рассмотрена при обсуждении функции lseek
в гл. 7. (В нашей команде tail
есть флаг -r
, который определяет печать строк в обратном порядке, заменяя команду backwards
).
При обычной обработке входная строка разбивается на поля. Эту операцию можно выполнить с помощью встроенной функции split
над любой строкой:
n = split(s, arr, sep)
Строка s
разбивается на поля, записываемые в элементы массива arr
от 1 до n
. Используется символ разделения полей sep
, если он задан; в противном случае применяется текущее значение переменной FS
. Например, обращение split($0, а, ":")
разбивает входную строку на столбцы, что подходит для обработки файла /etc/passwd
, поэтому обращение split("9/29/83", date, "/")
разбивает дату по символам дробной черты.
Читать дальше
Конец ознакомительного отрывка
Купить книгу