[https://habr.com/ru/company/ruvds/blog/327754/](https://habr.com/ru/company/ruvds/blog/327754/) --- В прошлый раз мы говорили о потоковом редакторе [sed](https://habrahabr.ru/company/ruvds/blog/327530/) и рассмотрели немало примеров обработки текста с его помощью. Sed способен решать многие задачи, но есть у него и ограничения. Иногда нужен более совершенный инструмент для обработки данных, нечто вроде языка программирования. Собственно говоря, такой инструмент — awk. Утилита awk, или точнее GNU awk, в сравнении с sed, выводит обработку потоков данных на более высокий уровень. Благодаря awk в нашем распоряжении оказывается язык программирования, а не довольно скромный набор команд, отдаваемых редактору. С помощью языка программирования awk можно выполнять следующие действия: - Объявлять переменные для хранения данных. - Использовать арифметические и строковые операторы для работы с данными. - Использовать структурные элементы и управляющие конструкции языка, такие, как оператор if-then и циклы, что позволяет реализовать сложные алгоритмы обработки данных. - Создавать форматированные отчёты. Если говорить лишь о возможности создавать форматированные отчёты, которые удобно читать и анализировать, то это оказывается очень кстати при работе с лог-файлами, которые могут содержать миллионы записей. Но awk — это намного больше, чем средство подготовки отчётов. ## Особенности вызова awk Схема вызова awk выглядит так: ``` $ awk options program file ``` Awk воспринимает поступающие к нему данные в виде набора записей. Записи представляют собой наборы полей. Упрощенно, если не учитывать возможности настройки awk и говорить о некоем вполне обычном тексте, строки которого разделены символами перевода строки, запись — это строка. Поле — это слово в строке. Рассмотрим наиболее часто используемые ключи командной строки awk: ``` -F fs — позволяет указать символ-разделитель для полей в записи. -f file — указывает имя файла, из которого нужно прочесть awk-скрипт. -v var=value — позволяет объявить переменную и задать её значение по умолчанию, которое будет использовать awk. -mf N — задаёт максимальное число полей для обработки в файле данных. -mr N — задаёт максимальный размер записи в файле данных. -W keyword — позволяет задать режим совместимости или уровень выдачи предупреждений awk. ``` Настоящая мощь awk скрывается в той части команды его вызова, которая помечена выше как `program`. Она указывает на файл awk-скрипта, написанный программистом и предназначенный для чтения данных, их обработки и вывода результатов. ## Чтение awk-скриптов из командной строки Скрипты awk, которые можно писать прямо в командной строке, оформляются в виде текстов команд, заключённых в фигурные скобки. Кроме того, так как awk предполагает, что скрипт представляет собой текстовую строку, его нужно заключить в одинарные кавычки: ``` $ awk '{print "Welcome to awk command tutorial"}' ``` Запустим эту команду… И ничего не произойдёт Дело тут в том, что мы, при вызове awk, не указали файл с данными. В подобной ситуации awk ожидает поступления данных из [STDIN](https://habrahabr.ru/company/ruvds/blog/326594/). Поэтому выполнение такой команды не приводит к немедленно наблюдаемым эффектам, но это не значит, что awk не работает — он ждёт входных данных из `STDIN`. Если теперь ввести что-нибудь в консоль и нажать `Enter`, awk обработает введённые данные с помощью скрипта, заданного при его запуске. Awk обрабатывает текст из потока ввода построчно, этим он похож на sed. В нашем случае awk ничего не делает с данными, он лишь, в ответ на каждую новую полученную им строку, выводит на экран текст, заданный в команде `print`. ![[5a19a94cad5893fc2194fb599cad5422.png]] _Первый запуск awk, вывод на экран заданного текста_ Что бы мы ни ввели, результат в данном случае будет одним и тем же — вывод текста. Для того, чтобы завершить работу awk, нужно передать ему символ конца файла (EOF, End-of-File). Сделать это можно, воспользовавшись сочетанием клавиш `CTRL + D`. Неудивительно, если этот первый пример показался вам не особо впечатляющим. Однако, самое интересное — впереди. ## Позиционные переменные, хранящие данные полей Одна из основных функций awk заключается в возможности манипулировать данными в текстовых файлах. Делается это путём автоматического назначения переменной каждому элементу в строке. По умолчанию awk назначает следующие переменные каждому полю данных, обнаруженному им в записи: - `$0 —` представляет всю строку текста (запись). - `$1 —` первое поле. - `$2 —` второе поле. - `$n —` n-ное поле. Поля выделяются из текста с использованием символа-разделителя. По умолчанию — это пробельные символы вроде пробела или символа табуляции. Рассмотрим использование этих переменных на простом примере. А именно, обработаем файл, в котором содержится несколько строк (этот файл показан на рисунке ниже) с помощью такой команды: ``` $ awk '{print $1}' myfile ``` ![[cf0b80d4a6ddb34d0b2f15c7ea54557a.png]] _Вывод в консоль первого поля каждой строки_ Здесь использована переменная `$1`, которая позволяет получить доступ к первому полю каждой строки и вывести его на экран. Иногда в некоторых файлах в качестве разделителей полей используется что-то, отличающееся от пробелов или символов табуляции. Выше мы упоминали ключ awk `-F`, который позволяет задать необходимый для обработки конкретного файла разделитель: ``` $ awk -F: '{print $1}' /etc/passwd ``` ![[2bf8033b122fdf3960311ebb80a67779.png]] _Указание символа-разделителя при вызове awk_ Эта команда выводит первые элементы строк, содержащихся в файле `/etc/passwd`. Так как в этом файле в качестве разделителей используются двоеточия, именно этот символ был передан awk после ключа `-F`. ## Использование нескольких команд Вызов awk с одной командой обработки текста — подход очень ограниченный. Awk позволяет обрабатывать данные с использованием многострочных скриптов. Для того, чтобы передать awk многострочную команду при вызове его из консоли, нужно разделить её части точкой с запятой: ``` $ echo "My name is Tom" | awk '{$4="Adam"; print $0}' ``` ![[a8c5b92921519f181cd5b2383956ffcb.png]] Вызов awk из командной строки с передачей ему многострочного скрипта В данном примере первая команда записывает новое значение в переменную `$4`, а вторая выводит на экран всю строку. ## Чтение скрипта awk из файла Awk позволяет хранить скрипты в файлах и ссылаться на них, используя ключ `-f`. Подготовим файл `testfile`, в который запишем следующее: ``` {print $1 " has a  home directory at " $6} ``` Вызовем awk, указав этот файл в качестве источника команд: ``` $ awk -F: -f testfile /etc/passwd ``` ![[b0b532a2f0c6597bb533bda90c747217.png]] _Вызов awk с указанием файла скрипта_ Тут мы выводим из файла `/etc/passwd` имена пользователей, которые попадают в переменную `$1`, и их домашние директории, которые попадают в `$6`. Обратите внимание на то, что файл скрипта задают с помощью ключа `-f`, а разделитель полей, двоеточие в нашем случае, с помощью ключа `-F`. В файле скрипта может содержаться множество команд, при этом каждую из них достаточно записывать с новой строки, ставить после каждой точку с запятой не требуется. Вот как это может выглядеть: ``` { text = " has a  home directory at " print $1 text $6 } ``` Тут мы храним текст, используемый при выводе данных, полученных из каждой строки обрабатываемого файла, в переменной, и используем эту переменную в команде `print`. Если воспроизвести предыдущий пример, записав этот код в файл `testfile`, выведено будет то же самое. ## Выполнение команд до начала обработки данных Иногда нужно выполнить какие-то действия до того, как скрипт начнёт обработку записей из входного потока. Например — создать шапку отчёта или что-то подобное. Для этого можно воспользоваться ключевым словом `BEGIN`. Команды, которые следуют за `BEGIN`, будут исполнены до начала обработки данных. В простейшем виде это выглядит так: ``` $ awk 'BEGIN {print "Hello World!"}' ``` А вот — немного более сложный пример: ``` $ awk 'BEGIN {print "The File Contents:"} {print $0}' myfile ``` ![[c50282673675bee9a49dfd9b6dfe32ea.png]] _Выполнение команд до начала обработки данных_ Сначала awk исполняет блок `BEGIN`, после чего выполняется обработка данных. Будьте внимательны с одинарными кавычками, используя подобные конструкции в командной строке. Обратите внимание на то, что и блок `BEGIN`, и команды обработки потока, являются в представлении awk одной строкой. Первая одинарная кавычка, ограничивающая эту строку, стоит перед `BEGIN`. Вторая — после закрывающей фигурной скобки команды обработки данных. ## Выполнение команд после окончания обработки данных Ключевое слово `END` позволяет задавать команды, которые надо выполнить после окончания обработки данных: ``` $ awk 'BEGIN {print "The File Contents:"} {print $0} END {print "End of File"}' myfile ``` ![[a32206c12e4c7628696cb62aed26b775.png]] Результаты работы скрипта, в котором имеются блоки BEGIN и END После завершения вывода содержимого файла, awk выполняет команды блока `END`. Это полезная возможность, с её помощью, например, можно сформировать подвал отчёта. Теперь напишем скрипт следующего содержания и сохраним его в файле `myscript`: ``` BEGIN { print "The latest list of users and shells" print " UserName \t HomePath" print "-------- \t -------" FS=":" } { print $1 " \t " $6 } END { print "The end" } ``` Тут, в блоке `BEGIN`, создаётся заголовок табличного отчёта. В этом же разделе мы указываем символ-разделитель. После окончания обработки файла, благодаря блоку `END`, система сообщит нам о том, что работа окончена. Запустим скрипт: ``` $ awk -f myscript  /etc/passwd ``` ![[1090704fb0f7853ce09f4fdc7d813c9d.png]] _Обработка файла /etc/passwd с помощью awk-скрипта_ Всё, о чём мы говорили выше — лишь малая часть возможностей awk. Продолжим освоение этого полезного инструмента. ## Встроенные переменные: настройка процесса обработки данных Утилита awk использует встроенные переменные, которые позволяют настраивать процесс обработки данных и дают доступ как к обрабатываемым данным, так и к некоторым сведениям о них. Мы уже рассматривали позиционные переменные — `$1`, `$2`, `$3`, которые позволяют извлекать значения полей, работали мы и с некоторыми другими переменными. На самом деле, их довольно много. Вот некоторые из наиболее часто используемых: ``` FIELDWIDTHS — разделённый пробелами список чисел, определяющий точную ширину каждого поля данных с учётом разделителей полей. FS — уже знакомая вам переменная, позволяющая задавать символ-разделитель полей. RS — переменная, которая позволяет задавать символ-разделитель записей. OFS — разделитель полей на выводе awk-скрипта. ORS — разделитель записей на выводе awk-скрипта. ``` По умолчанию переменная `OFS` настроена на использование пробела. Её можно установить так, как нужно для целей вывода данных: ``` $ awk 'BEGIN{FS=":"; OFS="-"} {print $1,$6,$7}' /etc/passwd ``` ![[a92f855d88053f7a0538abc1c3b57600.png]] _Установка разделителя полей выходного потока_ Переменная `FIELDWIDTHS` позволяет читать записи без использования символа-разделителя полей. В некоторых случаях, вместо использования разделителя полей, данные в пределах записей расположены в колонках постоянной ширины. В подобных случаях необходимо задать переменную `FIELDWIDTHS` таким образом, чтобы её содержимое соответствовало особенностям представления данных. При установленной переменной `FIELDWIDTHS` awk будет игнорировать переменную `FS` и находить поля данных в соответствии со сведениями об их ширине, заданными в `FIELDWIDTHS`. Предположим, имеется файл `testfile`, содержащий такие данные: ``` 1235.9652147.91 927-8.365217.27 36257.8157492.5 ``` Известно, что внутренняя организация этих данных соответствует шаблону 3-5-2-5, то есть, первое поле имеет ширину 3 символа, второе — 5, и так далее. Вот скрипт, который позволит разобрать такие записи: ``` $ awk 'BEGIN{FIELDWIDTHS="3 5 2 5"}{print $1,$2,$3,$4}' testfile ``` ![[b9b46c4ae70cc3c2cb2db7107dcdf48e.png]] _Использование переменной FIELDWIDTHS_ Посмотрим на то, что выведет скрипт. Данные разобраны с учётом значения переменной `FIELDWIDTHS`, в результате числа и другие символы в строках разбиты в соответствии с заданной шириной полей. Переменные `RS` и `ORS` задают порядок обработки записей. По умолчанию `RS` и `ORS` установлены на символ перевода строки. Это означает, что awk воспринимает каждую новую строку текста как новую запись и выводит каждую запись с новой строки. Иногда случается так, что поля в потоке данных распределены по нескольким строкам. Например, пусть имеется такой файл с именем `addresses`: ``` Person Name 123 High Street (222) 466-1234 Another person 487 High Street (523) 643-8754 ``` Если попытаться прочесть эти данные при условии, что `FS` и `RS` установлены в значения по умолчанию, awk сочтёт каждую новую строку отдельной записью и выделит поля, опираясь на пробелы. Это не то, что нам в данном случае нужно. Для того, чтобы решить эту проблему, в `FS` надо записать символ перевода строки. Это укажет awk на то, что каждая строка в потоке данных является отдельным полем. Кроме того, в данном примере понадобится записать в переменную `RS` пустую строку. Обратите внимание на то, что в файле блоки данных о разных людях разделены пустой строкой. В результате awk будет считать пустые строки разделителями записей. Вот как всё это сделать: ``` $ awk 'BEGIN{FS="\n"; RS=""} {print $1,$3}' addresses ``` ![[5f03e528de8e4355a16769871035e46d.png]] _Результаты настройки переменных RS и FS_ Как видите, awk, благодаря таким настройкам переменных, воспринимает строки из файла как поля, а разделителями записей становятся пустые строки. ## Встроенные переменные: сведения о данных и об окружении Помимо встроенных переменных, о которых мы уже говорили, существуют и другие, которые предоставляют сведения о данных и об окружении, в котором работает awk: ``` ARGC — количество аргументов командной строки. ARGV — массив с аргументами командной строки. ARGIND — индекс текущего обрабатываемого файла в массиве ARGV. ENVIRON — ассоциативный массив с переменными окружения и их значениями. ERRNO — код системной ошибки, которая может возникнуть при чтении или закрытии входных файлов. FILENAME — имя входного файла с данными. FNR — номер текущей записи в файле данных. IGNORECASE — если эта переменная установлена в ненулевое значение, при обработке игнорируется регистр символов. NF — общее число полей данных в текущей записи. NR — общее число обработанных записей. ``` Переменные `ARGC` и `ARGV` позволяют работать с аргументами командной строки. При этом скрипт, переданный awk, не попадает в массив аргументов `ARGV`. Напишем такой скрипт: ``` $ awk 'BEGIN{print ARGC,ARGV[1]}' myfile ``` После его запуска можно узнать, что общее число аргументов командной строки — 2, а под индексом 1 в массиве `ARGV` записано имя обрабатываемого файла. В элементе массива с индексом 0 в данном случае будет «awk». ![[2e815abfd2b87f1a83cbebddba6d4d19.png]] _Работа с параметрами командной строки_ Переменная `ENVIRON` представляет собой ассоциативный массив с переменными среды. Опробуем её: ``` $ awk ' BEGIN{ print ENVIRON["HOME"] print ENVIRON["PATH"] }' ``` ![[94ae22cacf533cf05ce5a8c6cbb0d816.png]] _Работа с переменными среды_ Переменные среды можно использовать и без обращения к `ENVIRON`. Сделать это, например, можно так: ``` $  echo | awk -v home=$HOME '{print "My home is " home}' ``` ![[50cb5580ee7438efd090b326d5af3a15.png]] _Работа с переменными среды без использования ENVIRON_ Переменная `NF` позволяет обращаться к последнему полю данных в записи, не зная его точной позиции: ``` $ awk 'BEGIN{FS=":"; OFS=":"} {print $1,$NF}' /etc/passwd ``` ![[619da6d74f1e59ed5c94800d58b817f2.png]] _Пример использования переменной NF_ Эта переменная содержит числовой индекс последнего поля данных в записи. Обратиться к данному полю можно, поместив перед `NF` знак `$`. Переменные `FNR` и `NR`, хотя и могут показаться похожими, на самом деле различаются. Так, переменная `FNR` хранит число записей, обработанных в текущем файле. Переменная `NR` хранит общее число обработанных записей. Рассмотрим пару примеров, передав awk один и тот же файл дважды: ``` $ awk 'BEGIN{FS=","}{print $1,"FNR="FNR}' myfile myfile ``` ![[2450b252839c00764accd771336fe518.png]] _Исследование переменной FNR_ Передача одного и того же файла дважды равносильна передаче двух разных файлов. Обратите внимание на то, что `FNR` сбрасывается в начале обработки каждого файла. Взглянем теперь на то, как ведёт себя в подобной ситуации переменная `NR`: ``` $ awk ' BEGIN {FS=","} {print $1,"FNR="FNR,"NR="NR} END{print "There were",NR,"records processed"}' myfile myfile ``` ![[9814bd85ce8fc22a2299f3ce35cd813e.png]] _Различие переменных NR и FNR_ Как видно, `FNR`, как и в предыдущем примере, сбрасывается в начале обработки каждого файла, а вот `NR`, при переходе к следующему файлу, сохраняет значение. ## Пользовательские переменные Как и любые другие языки программирования, awk позволяет программисту объявлять переменные. Имена переменных могут включать в себя буквы, цифры, символы подчёркивания. Однако, они не могут начинаться с цифры. Объявить переменную, присвоить ей значение и воспользоваться ей в коде можно так: ``` $ awk ' BEGIN{ test="This is a test" print test }' ``` ![[71150395079a584116811d6635023259.png]] _Работа с пользовательской переменной_ ## Условный оператор Awk поддерживает стандартный во многих языках программирования формат условного оператора `if-then-else`. Однострочный вариант оператора представляет собой ключевое слово `if`, за которым, в скобках, записывают проверяемое выражение, а затем — команду, которую нужно выполнить, если выражение истинно. Например, есть такой файл с именем `testfile`: ``` 10 15 6 33 45 ``` Напишем скрипт, который выводит числа из этого файла, большие 20: ``` $ awk '{if ($1 > 20) print $1}' testfile ``` ![[bfa877e321ef62fba8c76da8e967d751.png]] _Однострочный оператор if_ Если нужно выполнить в блоке `if` несколько операторов, их нужно заключить в фигурные скобки: ``` $ awk '{ if ($1 > 20) { x = $1 * 2 print x } }' testfile ``` ![[8e1c0b8db9cffa7428dda1af8bf3ebcb.png]] _Выполнение нескольких команд в блоке if_ Как уже было сказано, условный оператор awk может содержать блок `else`: ``` $ awk '{ if ($1 > 20) { x = $1 * 2 print x } else { x = $1 / 2 print x }}' testfile ``` ![[c53ec3762242952c072e9277b5d97593.png]] _Условный оператор с блоком else_ Ветвь `else` может быть частью однострочной записи условного оператора, включая в себя лишь одну строку с командой. В подобном случае после ветви `if`, сразу перед `else`, надо поставить точку с запятой: ``` $ awk '{if ($1 > 20) print $1 * 2; else print $1 / 2}' testfile ``` ![[e002f0a1a7d37436714f9f5fc93c8c73.png]] Условный оператор, содержащий ветви 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 ``` ![[qUE7sqkjSz-nGb4j4dYU15V0M9eLPXSuztbbmFCsjPzJEXRL-xosMnw2fdMd_4YAv_5fFnvt3Pijrggt_nt0vmoLzzfycbI8Uhh57lNMPu0TSYN-Y-mTWKozYoxrqy5Uz3jHDkcRnumMMnQUkw]] _Обработка данных в цикле 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 ``` ![[0VV0H2jGWnzz9I7z7GaQskjeH7qhM06ut-ssXOOA0HODAF5Tp801r9YD7j2xLQlAtJpBUwGkacfB7tz2SH4ZFcR2j-zRl6KNUZMGhVeZgv8t2PEvK2r4CQ8DfLkYGqf7_RJRtrYj20i-NMKn3w]] _Команда break в цикле while_ ## Цикл for Циклы `for` используются во множестве языков программировании. Поддерживает их и awk. Решим задачу расчёта среднего значения числовых полей с использованием такого цикла: ``` $ awk '{ total = 0 for (i = 1; i < 4; i++) { total += $i } avg = total / 3 print "Average:",avg }' testfile ``` ![[hmsFRQrUjqzTNGTmOf42XfHPjerCVY3y8EWViFKrXFBkugCrKSmgz0ei_JK3LSkOfqQDgok0iqOGgRk3LUKdhbLXNP_7iyxjOe_2hi-iObr1QxrMIWkWvYizkxUPXTiirZetpmn4vL2kBqFHvg]] _Цикл 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 }' ``` ![[32PdPiqkHvNTKbPq6tfVcEyb9se3YI54X_UA2yJbOWlJ5KYJfxTFTWTaXALHOIWO-WD5Bn79Q7b0c6wW6gUnL83WaqKxMvv8z3OGeZh5WEiLRbEYK0DHXfUtQMSPkykZsOhIpH5M2-wARhCvYw]] _Форматирование выходных данных с помощью printf_ Тут, в качестве примера, мы выводим число в экспоненциальной записи. Полагаем, этого достаточно для того, чтобы вы поняли основную идею, на которой построена работа с `printf`. ## Встроенные математические функции При работе с awk программисту доступны [встроенные функции](https://www.gnu.org/software/gawk/manual/html_node/Built_002din.html#Built_002din). В частности, это математические и строковые функции, функции для работы со временем. Вот, например, список математических функций, которыми можно пользоваться при разработке 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}' ``` ![[wFI2nUqVLj0duMPEafJs2MtGk7oETB1zCsm53GTzG30l5UjYDWb3igdtB_DULzzN8Mu40_XdSUoZj9egx-nCl11ct_-hcukCfcAVQ-CvD5qUCflo_h8CfVYvNZyWG6DNRJOg4QWW_huMOioX9Q]] _Работа с математическими функциями_ ## Строковые функции Awk поддерживает множество [строковых функций](https://www.gnu.org/software/gawk/manual/html_node/String-Functions.html#String-Functions). Все они устроены более или менее одинаково. Вот, например, функция `toupper`: ``` $ awk 'BEGIN{x = "likegeeks"; print toupper(x)}' ``` ![[1ef4HRdqEbczINRJIehv3fZ4737nmYjqj7BcDKnEIw9oQlV_KQEbn2QSGXsCT79jV6AHJify_Ik0RtTQiXTlO802hycQdkx4dLN_nJV4AeRX-zsGsu8JUSKszyfxZUq2daDZ-fYd752qViDdFQ]] _Использование строковой функции toupper_ Эта функция преобразует символы, хранящиеся в переданной ей строковой переменной, к верхнему регистру. ## Пользовательские функции При необходимости вы можете создавать собственные функции awk. Такие функции можно использовать так же, как встроенные: ``` $ awk ' function myprint() { printf "The user %s has home path at %s\n", $1,$6 } BEGIN{FS=":"} { myprint() }' /etc/passwd ``` ![[BTkYWVuNkMUnAHf4hA1ZksVnjTd68TMa6Drb04hnCqa8IxjR4TBTyA_r6u5CNz6fWCEy32nJIOV9J4Aj1gFqDXaeL8IjOZD76aj4cOBTfUi_Zp6kjlQ_LzoFFDiRV8NWuTVmV5bnJtn-9yHvqA]] _Использование собственной функции_ В примере используется заданная нами функция `myprint`, которая выводит данные. ## Итоги Сегодня мы разобрали основы awk. Это мощнейший инструмент обработки данных, масштабы которого сопоставимы с отдельным языком программирования. Вы не могли не заметить, что многое из того, о чём мы говорим, не так уж и сложно для понимания, а зная основы, уже можно что-то автоматизировать, но если копнуть поглубже, вникнуть в документацию… Вот, например, [The GNU Awk User’s Guide](https://www.gnu.org/software/gawk/manual/html_node/index.html). В этом руководстве впечатляет уже одно то, что оно ведёт свою историю с 1989-го (первая версия awk, кстати, появилась в 1977-м). Однако, сейчас вы знаете об awk достаточно для того, чтобы не потеряться в официальной документации и познакомиться с ним настолько близко, насколько вам того хочется. В следующий раз, кстати, мы поговорим о регулярных выражениях. Без них невозможно заниматься серьёзной обработкой текстов в bash-скриптах с применением sed и awk. Уважаемые читатели! Уверены, многие из вас периодически пользуются awk. Расскажите, как он помогает вам в работе?