Язык обработки шаблонов AWK -- часть 2
Действия
Простейшие операторы:
- exit — завершить выполнение программы
- next — перейти к следующей строке, управление на начало awk-программы
- break — выход из цикла
- continue — переход к следующей итерации
Структурные операторы:
- if (условие) {операторы} [else {операторы}]
- while (условие) {операторы}
- for (выражение; условие; выражение) {операторы}
- for (индекс in имя_массива) {операторы}
Структурные операторы в значительной степени аналогичны соответствующим операторам С.
В последнем случае для каждого индекса выполняется блок.
Текстовые индексы рассматриваются в лексикографическом порядке.
Примеры
$ awk '$4~/40/ {if($3<=1980) {print("Фамилия: " $1);
M["40"]++}} $4~/50/ {M["50"]++}
END {for(i in M) {print(" i =" i " M[" i "]=" M[i])}}' awk_test
Фамилия: Петров
Фамилия: Сидоров
i =40 M[40]=2
i =50 M[50]=1
$ awk ' BEGIN {ORS = " "}
{ for(k=NF; k>0; --k) {print $k}
{print RS}
}' awk_test | sed 's/^ //'
50 1980 К.И. Иванов
40 1978 А.П. Петров
40 1979 С.Л. Сидоров
65 1970 Л.Е. Федоров
Здесь, кроме изменения очередности полей в строке на противоположное (что делает цикл for), предварительно устанавливается выходной разделитель — пробел и весь результат предварительно выдается в одну строку, поэтому после обработки каждой строки выдается команда print RS для перевода выходной строки. С помощью sed убираем пробелы в начале строки.
Существенная деталь. Если запустить лишь базовую структуру
$ awk '{ for(k=NF; k>0; --k) {print $k}}' awk_test
50
1980
К.И.
Иванов
40
1978
А.П.
Петров
40
1979
С.Л.
Сидоров
65
1970
Л.Е.
Федоров
Однако, если поставим ; сразу после условия, т.е. сделаем пустое тело цикла, за пределы которого вынесен print $k, то получим исходную таблицу:
$ awk '{ for(k=NF; k>0; --k); {print $k}}' awk_test
Иванов К.И. 1980 50
Петров А.П. 1978 40
Сидоров С.Л. 1979 40
Федоров Л.Е. 1970 65
поскольку $k после выхода из цикла будет иметь значение 0,
а $0 — соответствует всей строке в качестве значения, то print $k будет после каждого цикла печатать полные строки.
Ввод и вывод данных
В общем случае в команде awk может быть указано несколько файлов.
- awk [-Fc] 'script.awk' [file ...]
- awk [-Fc] -f script.awk [file ...]
Файлы обрабатываются последовательно в указанном порядке.
Встроенные функции
- sin (x) синус x
- cos (x) косинус x
- exp (x) возведение в степень x
- log (x) натуральный логарифм x
- sqrt (x) извлечение корня x
- int (x) целая часть числа
- length (s) длина строки s
- printf (fmt, ...) форматирование(аналогично Си) по спецификации fmt.
- substr (s, m, n) подстрока в n символов строки s,начинающаяся с m.
- getline () чтение следующей строки.0 - конец файла, иначе 1.
- index (s1, s2) номер позиции,с которой s1 совпадает с s2, иначе 0.
- split (s, M, c) строка s разбивается элементы массива M по разделителю c (по умолчанию FS=" "); функция возвращает число полей.
Примеры
$ awk 'BEGIN {FS = "."; a=0}
length ($1) > 8 { print (length ($1), $0);
a++
} END {print ("Найдено строк: " a) }' awk_test
9 Сидоров С.Л. 1979 40
9 Федоров Л.Е. 1970 65
Найдено строк: 2
Здесь поля разделяются по ".", выбираются строки у которых длина первого поля больше 8-ми, и их длина length ($1) печатается перед строкой $0.
$ awk '{i=split($0, Name, ".");
for (j=1; j<=i; j++)
print ("Name[" j "]=" Name[j])
}' awk_test
Name[1]=Иванов К
Name[2]=И
Name[3]= 1980 50
Name[1]=Петров А
Name[2]=П
Name[3]= 1978 40
Name[1]=Сидоров С
Name[2]=Л
Name[3]= 1979 40
Name[1]=Федоров Л
Name[2]=Е
Name[3]= 1970 65
$ awk '{print (length)}' awk_test
35
35
33
33
Поскольку все строки были выровнены пробелами, а в длине строки учитываются все символы до конца строки.
$ awk '{printf "%7.2f %s\n", NR, $0}' awk_test
1.00 Иванов К.И. 1980 50
2.00 Петров А.П. 1978 40
3.00 Сидоров С.Л. 1979 40
4.00 Федоров Л.Е. 1970 65
$ awk '{printf "\t%s %s \n", NR, $0}' awk_test
1 Иванов К.И. 1980 50
2 Петров А.П. 1978 40
3 Сидоров С.Л. 1979 40
4 Федоров Л.Е. 1970 65
//на основе статьи Соловьева А.