Bash-скрипты, руководство в 11 частях — страница 14 из 19


$ awk 'BEGIN{print ARGC,ARGV[1]}' myfile

После его запуска можно узнать, что общее число аргументов командной строки — 2, а под индексом 1 в массиве ARGV записано имя обрабатываемого файла. В элементе массива с индексом 0 в данном случае будет «awk».


Работа с параметрами командной строки

Переменная ENVIRON представляет собой ассоциативный массив с переменными среды. Опробуем её:


$ awk '

BEGIN{

print ENVIRON["HOME"]

print ENVIRON["PATH"]

}'

Работа с переменными среды

Переменные среды можно использовать и без обращения к ENVIRON. Сделать это, например, можно так:


$  echo | awk -v home=$HOME '{print "My home is " home}'

Работа с переменными среды без использования ENVIRON

Переменная NF позволяет обращаться к последнему полю данных в записи, не зная его точной позиции:


$ awk 'BEGIN{FS=":"; OFS=":"} {print $1,$NF}' /etc/passwd

Пример использования переменной NF

Эта переменная содержит числовой индекс последнего поля данных в записи. Обратиться к данному полю можно, поместив перед NF знак $.


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


$ awk 'BEGIN{FS=","}{print $1,"FNR="FNR}' myfile myfile

Исследование переменной FNR

Передача одного и того же файла дважды равносильна передаче двух разных файлов. Обратите внимание на то, что FNR сбрасывается в начале обработки каждого файла.


Взглянем теперь на то, как ведёт себя в подобной ситуации переменная NR:


$ awk '

BEGIN {FS=","}

{print $1,"FNR="FNR,"NR="NR}

END{print "There were",NR,"records processed"}' myfile myfile

Различие переменных NR и FNR

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

Пользовательские переменные


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


$ awk '

BEGIN{

test="This is a test"

print test

}'

Работа с пользовательской переменной

Условный оператор


Awk поддерживает стандартный во многих языках программирования формат условного оператора if-then-else. Однострочный вариант оператора представляет собой ключевое слово if, за которым, в скобках, записывают проверяемое выражение, а затем — команду, которую нужно выполнить, если выражение истинно.


Например, есть такой файл с именем testfile:


10

15

6

33

45

Напишем скрипт, который выводит числа из этого файла, большие 20:


$ awk '{if ($1 > 20) print $1}' testfile

Однострочный оператор if

Если нужно выполнить в блоке if несколько операторов, их нужно заключить в фигурные скобки:


$ awk '{

if ($1 > 20)

{

x = $1 * 2

print x

}

}' testfile

Выполнение нескольких команд в блоке if

Как уже было сказано, условный оператор awk может содержать блок else:


$ awk '{

if ($1 > 20)

{

x = $1 * 2

print x

} else

{

x = $1 / 2

print x

}}' testfile

Условный оператор с блоком else

Ветвь else может быть частью однострочной записи условного оператора, включая в себя лишь одну строку с командой. В подобном случае после ветви if, сразу перед else, надо поставить точку с запятой:


$ awk '{if ($1 > 20) print $1 * 2; else print $1 / 2}' testfile

Условный оператор, содержащий ветви if и else, записанный в одну строку

Цикл while


Цикл while позволяет перебирать наборы данных, проверяя условие, которое остановит цикл.

Вот файл myfile, обработку которого мы хотим организовать с помощью цикла:


124 127 130

112 142 135

175 158 245

Напишем такой скрипт:


$ awk '{

total = 0

i = 1

while (i < 4)

{

total += $i

i++

}

avg = total / 3

print "Average:",avg

}' testfile

Обработка данных в цикле while

Цикл while перебирает поля каждой записи, накапливая их сумму в переменной total и увеличивая в каждой итерации на 1 переменную-счётчик i. Когда i достигнет 4, условие на входе в цикл окажется ложным и цикл завершится, после чего будут выполнены остальные команды — подсчёт среднего значения для числовых полей текущей записи и вывод найденного значения.


В циклах while можно использовать команды break и continue. Первая позволяет досрочно завершить цикл и приступить к выполнению команд, расположенных после него. Вторая позволяет, не завершая до конца текущую итерацию, перейти к следующей.


Вот как работает команда break:


$ awk '{

total = 0

i = 1

while (i < 4)

{

total += $i

if (i == 2)

break

i++

}

avg = total / 2

print "The average of the first two elements is:",avg

}' testfile

Команда break в цикле while

Цикл for


Циклы for используются во множестве языков программировании. Поддерживает их и awk. Решим задачу расчёта среднего значения числовых полей с использованием такого цикла:


$ awk '{

total = 0

for (i = 1; i < 4; i++)

{

total += $i

}

avg = total / 3

print "Average:",avg

}' testfile

Цикл for

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

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


Команда printf в awk позволяет выводить форматированные данные. Она даёт возможность настраивать внешний вид выводимых данных благодаря использованию шаблонов, в которых могут содержаться текстовые данные и спецификаторы форматирования.


Спецификатор форматирования — это специальный символ, который задаёт тип выводимых данных и то, как именно их нужно выводить. Awk использует спецификаторы форматирования как указатели мест вставки данных из переменных, передаваемых printf. Первый спецификатор соответствует первой переменной, второй спецификатор — второй, и так далее.


Спецификаторы форматирования записывают в таком виде:


%[modifier]control-letter

Вот некоторые из них:


c — воспринимает переданное ему число как код ASCII-символа и выводит этот символ.

d — выводит десятичное целое число.

i — то же самое, что и d.

e — выводит число в экспоненциальной форме.

f — выводит число с плавающей запятой.

g — выводит число либо в экспоненциальной записи, либо в формате с плавающей запятой, в зависимости от того, как получается короче.

o — выводит восьмеричное представление числа.

s — выводит текстовую строку.


Вот как форматировать выводимые данные с помощью printf:


$ awk 'BEGIN{

x = 100 * 100

printf "The result is: %e\n", x

}'

Форматирование выходных данных с помощью printf

Тут, в качестве примера, мы выводим число в экспоненциальной записи. Полагаем, этого достаточно для того, чтобы вы поняли основную идею, на которой построена работа с printf.

Встроенные математические функции


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


cos(x) — косинус x (x выражено в радианах).

sin(x) — синус x.

exp(x) — экспоненциальная функция.

int(x) — возвращает целую часть аргумента.

log(x) — натуральный логарифм.

rand() — возвращает случайное число с плавающей запятой в диапазоне 0 - 1.

sqrt(x) — квадратный корень из x.


Вот как пользоваться этими функциями:


$ awk 'BEGIN{x=exp(5); print x}'

Работа с математическими функциями

Строковые функции


Awk поддерживает множество строковых функций. Все они устроены более или менее одинаково. Вот, например, функция toupper:


$ awk 'BEGIN{x = "likegeeks"; print toupper(x)}'

Использование строковой функции toupper

Эта функция преобразует символы, хранящиеся в переданной ей строковой переменной, к верхнему регистру.

Пользовательские функции


При необходимости вы можете создавать собственные функции awk. Такие функции можно использовать так же, как встроенные:


$ awk '

function myprint()

{

printf "The user %s has home path at %s\n", $1,$6

}

BEGIN{FS=":"}

{

myprint()

}' /etc/passwd

Использование собственной функции

В примере используется заданная нами функция myprint, которая выводит данные.

Итоги


Сегодня мы разобрали основы awk. Это мощнейший инструмент обработки данных, масштабы которого сопоставимы с отдельным языком программирования.


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