$ 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, "/")
разбивает дату по символам дробной черты.
$ sed 1q /etc/passwd | awk '{split($0, a, ":"); print a[1]}'
root
$ echo 9/29/83 | awk '{split($0, date, "/"); print date[3]}'
83
$
В табл. 4.5 перечислены встроенные функции
awk
.
cos(expr)
| Косинус expr
|
exp(expr)
| Возведение в степень expr
|
getline()
| Чтение следующей входной строки; возвращает 0 в случае конца файла, в противном случае 1 |
index(s1, s2)
| Положение строки s2 в s1 ; возвращает 0, если строка не входит |
int(expr)
| Целая часть expr ; округляет по минимуму |
length(s)
| Длина строки s
|
log(expr)
| Натуральный логарифм expr
|
sin(expr)
| Синус expr
|
split(s, a, c)
| Разбиение s на а[1] ... a[n] по символу c ; возвращает n
|
sprintf(fmt, ...)
| Форматирование в соответствии со спецификацией fmt
|
substr(s,m,n)
| Подстрока в n символов строки s , начинающаяся с индекса m
|