Главная страница

вцуйф ауцй. Bash скрипты


Скачать 3.58 Mb.
НазваниеBash скрипты
Анкорвцуйф ауцй
Дата15.08.2022
Размер3.58 Mb.
Формат файлаpdf
Имя файлаbash.pdf
ТипРуководство
#646431
страница4 из 6
1   2   3   4   5   6
Символы-разделители Представьте, что нужно заменить /bin/bash на /bin/csh в файле /etc/passwd. Задача не такая ужи сложная
$ sed 's/\/bin\/bash/\/bin\/csh/' /etc/passwd Однако, выглядит всё это не очень-то хорошо. Всё дело в том, что так как прямые слэши используются в роли символов-разделителей, такие же символы в передаваемых sed строках приходится экранировать. В результате страдает читаемость команды. К счастью, sed позволяет нам самостоятельно задавать символы-разделители для использования их в команде замены. Разделителем считается первый символ, который будет встречен после s:
$ sed 's!/bin/bash!/bin/csh!' /etc/passwd В данном случаев качестве разделителя использован восклицательный знак, в результате код легче читать ион выглядит куда опрятнее, чем прежде.

83 Выбор фрагментов текста для обработки До сих пор мы вызывали sed для обработки всего переданного редактору потока данных. В некоторых случаях с помощью sed надо обработать лишь какую-то часть текста — некую конкретную строку или группу строк. Для достижения такой цели можно воспользоваться двумя подходами
● Задать ограничение на номера обрабатываемых строк.
● Указать фильтр, соответствующие которому строки нужно обработать. Рассмотрим первый подход. Тут допустимо два варианта. Первый, рассмотренный ниже, предусматривает указание номера одной строки, которую нужно обработать
$ sed '2s/test/another test/' myfile Обработка только одной строки, номер который задан при вызове sed Второй вариант — диапазон строк
$ sed '2,3s/test/another test/' myfile Обработка диапазона строк Кроме того, можно вызвать команду замены так, чтобы файл был обработан начиная с некоей строки и до конца
$ sed '2,$s/test/another test/' myfile Обработка файла начиная со второй строки и до конца Для того, чтобы обрабатывать с помощью команды замены только строки, соответствующие заданному фильтру, команду надо вызвать так
$ sed '/likegeeks/s/bash/csh/' /etc/passwd По аналогии стем, что было рассмотрено выше, шаблон передаётся перед именем команды s.

84 Обработка строк, соответствующих фильтру Тут мы использовали очень простой фильтр. Для того, чтобы в полной мере раскрыть возможности данного подхода, можно воспользоваться регулярными выражениями. О них мы поговорим водном из следующих материалов этой серии. Удаление строк Утилита sed годится не только для замены одних последовательностей символов в строках на другие. Се помощью, а именно, используя команду d, можно удалять строки из текстового потока. Вызов команды выглядит так
$ sed '3d' myfile Мы хотим, чтобы из текста была удалена третья строка. Обратите внимание на то, что речь не идёт о файле. Файл останется неизменным, удаление отразится лишь на выводе, который сформирует sed. Удаление третьей строки Если при вызове команды d не указать номер удаляемой строки, удалены будут все строки потока. Вот как применить команду d к диапазону строк
$ sed '2,3d' myfile Удаление диапазона строк А вот как удалить строки, начиная с заданной — и до конца файла
$ sed '3,$d' myfile

85 Удаление строк до конца файла Строки можно удалять и по шаблону
$ sed '/test/d' myfile Удаление строк по шаблону При вызове d можно указывать пару шаблонов — будут удалены строки, в которых встретится шаблон, и те строки, которые находятся между ними
$ sed '/second/,/fourth/d' myfile Удаление диапазона строк с использованием шаблонов Вставка текста в поток С помощью sed можно вставлять данные в текстовый поток, используя команды i и a:
● Команда i добавляет новую строку перед заданной.
● Команда a добавляет новую строку после заданной. Рассмотрим пример использования команды i:
$ echo "Another test" | sed 'i\First test '

86 Команда i Теперь взглянем на команду a:
$ echo "Another test" | sed 'a\First test ' Команда a Как видно, эти команды добавляют текст доили после данных из потока. Что если надо добавить строку где-нибудь посередине Тут нам поможет указание номера опорной строки в потоке, или шаблона. Учтите, что адресация строк в виде диапазона тут не подойдёт. Вызовем команду i, указав номер строки, перед которой надо вставить новую строку
$ sed '2i\This is the inserted line.' myfile Команда i с указанием номера опорной строки Проделаем тоже самое с командой a:
$ sed '2a\This is the appended line.' myfile

87 Команда a с указанием номера опорной строки Обратите внимание на разницу в работе команд i и a. Первая вставляет новую строку до указанной, вторая — после. Замена строк Команда c позволяет изменить содержимое целой строки текста в потоке данных. При её вызове нужно указать номер строки, вместо которой в поток надо добавить новые данные
$ sed '3c\This is a modified line.' myfile Замена строки целиком Если воспользоваться при вызове команды шаблоном в виде обычного текста или регулярного выражения, заменены будут все соответствующие шаблону строки
$ sed '/This is/c This is a changed line of text.' myfile Замена строк по шаблону Замена символов


88 Команда y работает с отдельными символами, заменяя их в соответствии с переданными ей при вызове данными
$ sed 'y/123/567/' myfile Замена символов Используя эту команду, нужно учесть, что она применяется ко всему текстовому потоку, ограничить её конкретными вхождениями символов нельзя. Вывод номеров строк Если вызвать sed, использовав команду =, утилита выведет номера строк в потоке данных
$ sed '=' myfile Вывод номеров строк Потоковый редактор вывел номера строк перед их содержимым. Если передать этой команде шаблон и воспользоваться ключом sed -n, выведены будут только номера строк, соответствующих шаблону
$ sed -n '/test/=' myfile Вывод номеров строк, соответствующих шаблону Чтение данных для вставки из файла


89 Выше мы рассматривали приёмы вставки данных в поток, указывая то, что надо вставить, прямо при вызове sed. В качестве источника данных можно воспользоваться и файлом. Для этого служит команда r, которая позволяет вставлять в поток данные из указанного файла. При её вызове можно указать номер строки, после которой надо вставить содержимое файла, или шаблон. Рассмотрим пример
$ sed '3r newfile' myfile Вставка в поток содержимого файла Тут содержимое файла newfile было вставлено после третьей строки файла myfile. Вот что произойдёт, если применить при вызове команды r шаблон
$ sed '/test/r newfile' myfile Использование шаблона при вызове команды r Содержимое файла будет вставлено после каждой строки, соответствующей шаблону. Пример Представим себе такую задачу. Есть файл, в котором имеется некая последовательность символов, сама по себе бессмысленная, которую надо заменить на данные, взятые из другого файла. А именно, пусть это будет файл newfile, в котором роль указателя места заполнения играет последовательность символов DATA. Данные, которые нужно подставить вместо DATA, хранятся в файле data.

90 Решить эту задачу можно, воспользовавшись командами r и d потокового редактора sed:
$ Sed '/DATA>/ { r newfile d}' myfile Замена указателя места заполнения на реальные данные Как видите, вместо заполнителя DATA sed добавил в выходной поток две строки из файла data. Итоги Сегодня мы рассмотрели основы работы с потоковым редактором sed. На самом деле, sed — это огромнейшая тема. Его изучение вполне можно сравнить с изучением нового языка программирования, однако, поняв основы, вы сможете освоить sed на любом необходимом вам уровне. В результате ваши возможности по обработке сего помощью текстов будет ограничивать лишь воображение. На сегодня это всё. В следующий раз поговорим о языке обработки данных awk.

91 скрипты, часть 8: язык обработки данных awk В прошлый раз мы говорили о потоковом редакторе sed и рассмотрели немало примеров обработки текста сего помощью. Sed способен решать многие задачи, но есть у него и ограничения. Иногда нужен более совершенный инструмент для обработки данных, нечто вроде языка программирования. Собственно говоря, такой инструмент — awk. Утилита awk, или точнее GNU awk, в сравнении с sed, выводит обработку потоков данных на более высокий уровень. Благодаря awk в нашем распоряжении оказывается язык программирования, а недовольно скромный набор команд, отдаваемых редактору. С помощью языка программирования awk можно выполнять следующие действия
● Объявлять переменные для хранения данных.
● Использовать арифметические и строковые операторы для работы сданными Использовать структурные элементы и управляющие конструкции языка, такие, как оператор if-then и циклы, что позволяет реализовать сложные алгоритмы обработки данных.
● Создавать форматированные отчёты. Если говорить лишь о возможности создавать форматированные отчёты, которые удобно читать и анализировать, то это оказывается очень кстати при работе с лог-файлами, которые могут содержать миллионы записей. Но awk — это намного больше, чем средство подготовки отчётов. Особенности вызова awk Схема вызова awk выглядит так
$ awk options program file
Awk воспринимает поступающие к нему данные в виде набора записей. Записи представляют собой наборы полей. Упрощенно, если не учитывать возможности настройки awk и говорить о некоем вполне обычном тексте, строки которого разделены символами перевода строки, запись — это строка. Поле — это слово в строке. Рассмотрим наиболее часто используемые ключи командной строки awk:
-F fs
— позволяет указать символ-разделитель для полей в записи.
-f file
— указывает имя файла, из которого нужно прочесть скрипт.
-v var=value
— позволяет объявить переменную и задать её значение по умолчанию, которое будет использовать awk.
-mf N
— задаёт максимальное число полей для обработки в файле данных.
-mr N
— задаёт максимальный размер записи в файле данных.
-W keyword
— позволяет задать режим совместимости или уровень выдачи предупреждений awk Настоящая мощь awk скрывается в той части команды его вызова, которая помечена выше как program. Она указывает на файл скрипта, написанный программистом и предназначенный для чтения данных, их обработки и вывода результатов. Чтение скриптов из командной строки Скрипты awk, которые можно писать прямо в командной строке, оформляются в виде текстов команд, заключённых в фигурные скобки. Кроме того, так как awk предполагает, что скрипт представляет собой текстовую строку, его нужно заключить в одинарные кавычки

92
$ awk '{print "Welcome to awk command tutorial"}' Запустим эту команду. И ничего не произойдёт Дело тут в том, что мы, при вызове awk, не указали файл сданными. В подобной ситуации awk ожидает поступления данных из
STDIN
. Поэтому выполнение такой команды не приводит к немедленно наблюдаемым эффектам, но это не значит, что awk не работает — он ждёт входных данных из STDIN. Если теперь ввести что-нибудь в консоль и нажать Enter, awk обработает введённые данные с помощью скрипта, заданного при его запуске. Awk обрабатывает текст из потока ввода построчно, этим он похож на sed. В нашем случае awk ничего не делает сданными, он лишь, в ответ на каждую новую полученную им строку, выводит на экран текст, заданный в команде print. Первый запуск awk, вывод на экран заданного текста Чтобы мы ни ввели, результат в данном случае будет одними тем же — вывод текста. Для того, чтобы завершить работу awk, нужно передать ему символ конца файла (EOF, End-of-File). Сделать это можно, воспользовавшись сочетанием клавиш CTRL + D. Неудивительно, если этот первый пример показался вам не особо впечатляющим. Однако, самое интересное — впереди. Позиционные переменные, хранящие данные полей Одна из основных функций awk заключается в возможности манипулировать данными в текстовых файлах. Делается это путём автоматического назначения переменной каждому элементу в строке. По умолчанию awk назначает следующие переменные каждому полю данных, обнаруженному им в записи
● $0 — представляет всю строку текста (запись.
● $1 — первое поле.
● $2 — второе поле.
● $n — n-ное поле. Поля выделяются из текста с использованием символа-разделителя. По умолчанию — это пробельные символы вроде пробела или символа табуляции. Рассмотрим использование этих переменных на простом примере. А именно, обработаем файл, в котором содержится несколько строк (этот файл показан на рисунке ниже) с помощью такой команды
$ awk '{print $1}' myfile

93 Вывод в консоль первого поля каждой строки Здесь использована переменная $1, которая позволяет получить доступ к первому полю каждой строки и вывести его на экран. Иногда в некоторых файлах в качестве разделителей полей используется что-то, отличающееся от пробелов или символов табуляции. Выше мы упоминали ключ awk -F, который позволяет задать необходимый для обработки конкретного файла разделитель
$ awk -F: '{print $1}' /etc/passwd Указание символа-разделителя при вызове awk Эта команда выводит первые элементы строк, содержащихся в файле /etc/passwd. Так как в этом файле в качестве разделителей используются двоеточия, именно этот символ был передан awk после ключа -F. Использование нескольких команд Вызов awk с одной командой обработки текста — подход очень ограниченный. Awk позволяет обрабатывать данные с использованием многострочных скриптов. Для того, чтобы передать awk многострочную команду при вызове его из консоли, нужно разделить её части точкой с запятой
$ echo "My name is Tom" | awk '{$4="Adam"; print $0}' Вызов awk из командной строки с передачей ему многострочного скрипта В данном примере первая команда записывает новое значение в переменную $4, а вторая выводит на экран всю строку.

94 Чтение скрипта awk из файла

Awk позволяет хранить скрипты в файлах и ссылаться на них, используя ключ -f. Подготовим файл testfile, в который запишем следующее
{print $1 " has a home directory at " $6} Вызовем awk, указав этот файл в качестве источника команд
$ awk -F: -f testfile /etc/passwd Вызов awk с указанием файла скрипта Тут мы выводим из файла /etc/passwd имена пользователей, которые попадают в переменную $1, и их домашние директории, которые попадают в $6. Обратите внимание на то, что файл скрипта задают с помощью ключа -f, а разделитель полей, двоеточие в нашем случае, с помощью ключа -F. В файле скрипта может содержаться множество команд, при этом каждую из них достаточно записывать с новой строки, ставить после каждой точку с запятой не требуется. Вот как это может выглядеть
{ text = " has a home directory at " print $1 text $6
} Тут мы храним текст, используемый при выводе данных, полученных из каждой строки обрабатываемого файла, в переменной, и используем эту переменную в команде print. Если воспроизвести предыдущий пример, записав этот код в файл testfile, выведено будет тоже самое. Выполнение команд до начала обработки данных Иногда нужно выполнить какие-то действия до того, как скрипт начнёт обработку записей из входного потока. Например — создать шапку отчёта или что-то подобное. Для этого можно воспользоваться ключевым словом BEGIN. Команды, которые следуют забудут исполнены до начала обработки данных. В простейшем виде это выглядит так

95
$ awk 'BEGIN {print "Hello World!"}' А вот — немного более сложный пример
$ awk 'BEGIN {print "The File Contents:"}
{print $0}' myfile Выполнение команд до начала обработки данных Сначала awk исполняет блок BEGIN, после чего выполняется обработка данных. Будьте внимательны с одинарными кавычками, используя подобные конструкции в командной строке. Обратите внимание на то, что и блоки команды обработки потока, являются в представлении awk одной строкой. Первая одинарная кавычка, ограничивающая эту строку, стоит перед BEGIN. Вторая — после закрывающей фигурной скобки команды обработки данных. Выполнение команд после окончания обработки данных Ключевое слово END позволяет задавать команды, которые надо выполнить после окончания обработки данных
$ awk 'BEGIN {print "The File Contents:"}
{print $0}
END {print "End of File"}' myfile Результаты работы скрипта, в котором имеются блоки BEGIN и END После завершения вывода содержимого файла, awk выполняет команды блока END. Это полезная возможность, се помощью, например, можно сформировать подвал отчёта. Теперь напишем скрипт следующего содержания и сохраним его в файле myscript:
BEGIN { print "The latest list of users and shells" print " UserName \t HomePath" print "-------- \t -------"

96
FS=":"
}
{ print $1 " \t " $6
}
END { print "The end"
} Тут, в блоке BEGIN, создаётся заголовок табличного отчёта. В этом же разделе мы указываем символ- разделитель. После окончания обработки файла, благодаря блоку END, система сообщит нам о том, что работа окончена. Запустим скрипт
$ awk -f myscript /etc/passwd Обработка файла /etc/passwd с помощью скрипта
Всё, о чём мы говорили выше — лишь малая часть возможностей awk. Продолжим освоение этого полезного инструмента. Встроенные переменные настройка процесса обработки данных Утилита awk использует встроенные переменные, которые позволяют настраивать процесс обработки данных и дают доступ как к обрабатываемым данным, таки к некоторым сведениям о них. Мы уже рассматривали позиционные переменные — $1, $2, $3, которые позволяют извлекать значения полей, работали мы и с некоторыми другими переменными. На самом деле, их довольно много. Вот некоторые из наиболее часто используемых
FIELDWIDTHS
— разделённый пробелами список чисел, определяющий точную ширину каждого поля данных с учётом разделителей полей.
FS
— уже знакомая вам переменная, позволяющая задавать символ-разделитель полей.
RS
— переменная, которая позволяет задавать символ-разделитель записей.

97
OFS
— разделитель полей на выводе скрипта.
ORS
— разделитель записей на выводе скрипта. По умолчанию переменная OFS настроена на использование пробела. Её можно установить так, как нужно для целей вывода данных
$ awk 'BEGIN{FS=":"; OFS="-"} {print $1,$6,$7}' /etc/passwd Установка разделителя полей выходного потока Переменная 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 Использование переменной FIELDWIDTHS Посмотрим на то, что выведет скрипт. Данные разобраны с учётом значения переменной
FIELDWIDTHS, в результате числа и другие символы в строках разбиты в соответствии с заданной шириной полей.

98 Переменные 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 Результаты настройки переменных RS и FS Как видите, awk, благодаря таким настройкам переменных, воспринимает строки из файла как поля, а разделителями записей становятся пустые строки. Встроенные переменные сведения о данных и об окружении Помимо встроенных переменных, о которых мы уже говорили, существуют и другие, которые предоставляют сведения о данных и об окружении, в котором работает awk:
ARGC
— количество аргументов командной строки.
ARGV
— массив с аргументами командной строки.
ARGIND
— индекс текущего обрабатываемого файла в массиве ARGV.
ENVIRON
— ассоциативный массив с переменными окружения и их значениями.
ERRNO
— код системной ошибки, которая может возникнуть при чтении или закрытии входных файлов.

99
FILENAME
— имя входного файла сданными номер текущей записи в файле данных.
IGNORECASE
— если эта переменная установлена в ненулевое значение, при обработке игнорируется регистр символов.
NF
— общее число полей данных в текущей записи.
NR
— общее число обработанных записей. Переменные ARGC и ARGV позволяют работать с аргументами командной строки. При этом скрипт, переданный awk, не попадает в массив аргументов ARGV. Напишем такой скрипт
$ 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

100 Переменная 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

101 Различие переменных NR и FNR Как видно, FNR, как ив предыдущем примере, сбрасывается вначале обработки каждого файла, а вот
NR, при переходе к следующему файлу, сохраняет значение. Пользовательские переменные Как и любые другие языки программирования, awk позволяет программисту объявлять переменные. Имена переменных могут включать в себя буквы, цифры, символы подчёркивания. Однако, они не могут начинаться с цифры. Объявить переменную, присвоить ей значение и воспользоваться ей в коде можно так
$ awk '
BEGIN{ test="This is a test" print test
}' Работа с пользовательской переменной Условный оператор
Awk поддерживает стандартный во многих языках программирования формат условного оператора if- then- else. Однострочный вариант оператора представляет собой ключевое слово if, за которым, в скобках, записывают проверяемое выражение, а затем — команду, которую нужно выполнить, если выражение истинно. Например, есть такой файл с именем testfile:
10 15 6

102 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

103
}}' 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++

104
} 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

105 Команда 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, самостоятельно инкрементировать счётчик. Форматированный вывод данных


106 Команда printf в awk позволяет выводить форматированные данные. Она даёт возможность настраивать внешний вид выводимых данных благодаря использованию шаблонов, в которых могут содержаться текстовые данные и спецификаторы форматирования. Спецификатор форматирования — это специальный символ, который задаёт тип выводимых данных и то, как именно их нужно выводить. Awk использует спецификаторы форматирования как указатели мест вставки данных из переменных, передаваемых printf. Первый спецификатор соответствует первой переменной, второй спецификатор — второй, итак далее. Спецификаторы форматирования записывают в таком виде
%[modifier]control-letter Вот некоторые из них c
— воспринимает переданное ему число как код символа и выводит этот символ. d
— выводит десятичное целое число. i
— тоже самое, что и d. e
— выводит число в экспоненциальной форме. f
— выводит число с плавающей запятой. g
— выводит число либо в экспоненциальной записи, либо в формате с плавающей запятой, в зависимости оттого, как получается короче. o
— выводит восьмеричное представление числа. s
— выводит текстовую строку. Вот как форматировать выводимые данные с помощью printf:
$ awk 'BEGIN{ x = 100 * 100 printf "The result is: %e\n", x
}' Форматирование выходных данных с помощью printf Тут, в качестве примера, мы выводим число в экспоненциальной записи. Полагаем, этого достаточно для того, чтобы вы поняли основную идею, на которой построена работа с printf. Встроенные математические функции При работе с awk программисту доступны встроенные функции. В частности, это математические и строковые функции, функции для работы со временем. Вот, например, список математических функций, которыми можно пользоваться при разработке скриптов cos(x)
— косинус x (x выражено в радианах. sin(x)
— синус x.

107 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

108 Использование собственной функции В примере используется заданная нами функция myprint, которая выводит данные. Итоги Сегодня мы разобрали основы awk. Это мощнейший инструмент обработки данных, масштабы которого сопоставимы с отдельным языком программирования. Вы не могли не заметить, что многое из того, о чём мы говорим, не так ужи сложно для понимания, а зная основы, уже можно что-то автоматизировать, но если копнуть поглубже, вникнуть в документацию. Вот, например,
The GNU Awk User’s Guide
. В этом руководстве впечатляет уже одно то, что оно ведёт свою историю с го (первая версия awk, кстати, появилась в м. Однако, сейчас вызнаете об awk достаточно для того, чтобы не потеряться в официальной документации и познакомиться с ним настолько близко, насколько вам того хочется. В следующий раз, кстати, мы поговорим о регулярных выражениях. Без них невозможно заниматься серьёзной обработкой текстов в bash- скриптах с применением sed и awk.

109 скрипты, часть 9: регулярные выражения Для того, чтобы полноценно обрабатывать тексты в скриптах с помощью sed и awk, просто необходимо разобраться с регулярными выражениями. Реализации этого полезнейшего инструмента можно найти буквально повсюду, и хотя устроены все регулярные выражения схожим образом, основаны на одних и тех же идеях, в разных средах работа сними имеет определённые особенности. Тут мы поговорим о регулярных выражениях, которые подходят для использования в сценариях командной строки Linux. Этот материал задуман как введение в регулярные выражения, рассчитанное на тех, кто может совершенно не знать о том, что это такое. Поэтому начнём с самого начала. Что такое регулярные выражения У многих, когда они впервые видят регулярные выражения, сразу же возникает мысль, что передними бессмысленное нагромождение символов. Но это, конечно, далеко не так. Взгляните, например, на это регулярное выражение
^([a-zA-Z0-9_\-\.\+]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$ На наш взгляд даже абсолютный новичок сходу поймёт, как оно устроено и зачем нужно :-). Если же вам не вполне понятно — просто читайте дальше и всё встанет на свои места. Регулярное выражение — это шаблон, пользуясь которым программы вроде sed или awk фильтруют тексты. В шаблонах используются обычные символы, представляющие сами себя, итак называемые метасимволы, которые играют особую роль, например, позволяя ссылаться на некие группы символов. Типы регулярных выражений Реализации регулярных выражений в различных средах, например, в языках программирования вроде
Java, Perl ив инструментах Linux вроде sed, awk и grep, имеют определённые особенности. Эти особенности зависят от так называемых движков обработки регулярных выражений, которые занимаются интерпретацией шаблонов. В Linux имеется два движка регулярных выражений
● Движок, поддерживающий стандарт POSIX Basic Regular Expression (BRE).
● Движок, поддерживающий стандарт POSIX Extended Regular Expression (ERE). Большинство утилит Linux соответствуют, как минимум, стандарту POSIX BRE, но некоторые утилиты в их числе — sed) понимают лишь некое подмножество стандарта BRE. Одна из причин такого ограничения — стремление сделать такие утилиты как можно более быстрыми в деле обработки текстов. Стандарт POSIX ERE часто реализуют в языках программирования. Он позволяет пользоваться большим количеством средств при разработке регулярных выражений. Например, это могут быть специальные последовательности символов для часто используемых шаблонов, вроде поискав тексте отдельных словили наборов цифр. Awk поддерживает стандарт ERE. Существует много способов разработки регулярных выражений, зависящих и от мнения программиста, и от особенностей движка, под который их создают. Непросто писать универсальные регулярные

110 выражения, которые сможет понять любой движок. Поэтому мы сосредоточимся на наиболее часто используемых регулярных выражениях и рассмотрим особенности их реализации для sed и awk. Регулярные выражения POSIX BRE Пожалуй, самый простой шаблон BRE представляет собой регулярное выражение для поиска точного вхождения последовательности символов в тексте. Вот как выглядит поиск строки в sed и awk:
$ echo "This is a test" | sed -n '/test/p'
$ echo "This is a test" | awk '/test/{print $0}' Поиск текста по шаблону в sed Поиск текста по шаблону в awk Можно заметить, что поиск заданного шаблона выполняется без учёта точного места нахождения текста в строке. Кроме того, не имеет значение и количество вхождений. После того, как регулярное выражение найдёт заданный текст в любом месте строки, строка считается подходящей и передаётся для дальнейшей обработки. Работая с регулярными выражениями нужно учитывать то, что они чувствительны к регистру символов
$ echo "This is a test" | awk '/Test/{print $0}'
$ echo "This is a test" | awk '/test/{print $0}' Регулярные выражения чувствительны к регистру Первое регулярное выражение совпадений не нашло, так как слово «test», начинающееся с заглавной буквы, в тексте не встречается. Второе же, настроенное на поиск слова, написанного прописными буквами, обнаружило в потоке подходящую строку. В регулярных выражениях можно использовать не только буквы, но и пробелы, и цифры
$ echo "This is a test 2 again" | awk '/test 2/{print $0}' Поиск фрагмента текста, содержащего пробелы и цифры


111 Пробелы воспринимаются движком регулярных выражений как обычные символы. Специальные символы При использовании различных символов в регулярных выражениях надо учитывать некоторые особенности. Так, существуют некоторые специальные символы, или метасимволы, использование которых в шаблоне требует особого подхода. Вот они
.*[]^${}\+?|() Если один из них нужен в шаблоне, его нужно будет экранировать с помощью обратной косой черты обратного слэша) — \. Например, если в тексте нужно найти знак доллара, его надо включить в шаблон, предварив символом экранирования. Скажем, имеется файл myfile с таким текстом
There is 10$ on my pocket Знак доллара можно обнаружить с помощью такого шаблона
$ awk '/\$/{print $0}' myfile Использование в шаблоне специального символа Кроме того, обратная косая черта — это тоже специальный символ, поэтому, если нужно использовать его в шаблоне, его тоже надо будет экранировать. Выглядит это как два слэша, идущих друг за другом
$ echo "\ is a special character" | awk '/\\/{print $0}' Экранирование обратного слэша Хотя прямой слэш и не входит в приведённый выше список специальных символов, попытка воспользоваться им в регулярном выражении, написанном для sed или awk, приведёт к ошибке
$ echo "3 / 2" | awk '///{print $0}' Неправильное использование прямого слэша в шаблоне Если он нужен, его тоже надо экранировать
$ echo "3 / 2" | awk '/\//{print $0}'

112 Экранирование прямого слэша Якорные символы Существуют два специальных символа для привязки шаблона к началу или к концу текстовой строки. Символ крышка — ^ позволяет описывать последовательности символов, которые находятся вначале текстовых строк. Если искомый шаблон окажется в другом месте строки, регулярное выражение на него не отреагирует. Выглядит использование этого символа так
$ echo "welcome to likegeeks website" | awk '/^likegeeks/{print $0}'
$ echo "likegeeks website" | awk '/^likegeeks/{print $0}' Поиск шаблона вначале строки Символ ^ предназначен для поиска шаблона вначале строки, при этом регистр символов также учитывается. Посмотрим, как это отразится на обработке текстового файла
$ awk '/^this/{print $0}' myfile Поиск шаблона вначале строки в тексте из файла При использовании sed, если поместить крышку где-нибудь внутри шаблона, она будет восприниматься как любой другой обычный символ
$ echo "This ^ is a test" | sed -n '/s ^/p' Крышка, находящаяся не вначале шаблона в sed В awk, при использовании такого же шаблона, данный символ надо экранировать
$ echo "This ^ is a test" | awk '/s \^/{print $0}' Крышка, находящаяся не вначале шаблона в awk

113 С поиском фрагментов текста, находящихся вначале строки мы разобрались. Что, если надо найти нечто, расположенное в конце строки В этом нам поможет знак доллара — $, являющийся якорным символом конца строки
$ echo "This is a test" | awk '/test$/{print $0}' Поиск текста, находящегося в конце строки Водном и том же шаблоне можно использовать оба якорных символа. Выполним обработку файла myfile, содержимое которого показано на рисунке ниже, с помощью такого регулярного выражения
$ awk '/^this is a test$/{print $0}' myfile Шаблон, в котором использованы специальные символы начала и конца строки Как видно, шаблон среагировал лишь на строку, полностью соответствующую заданной последовательности символов и их расположению. Вот как, пользуясь якорными символами, отфильтровать пустые строки
$ awk '!/^$/{print $0}' myfile В данном шаблоне использовал символ отрицания, восклицательный знак — !. Благодаря использованию такого шаблона выполняется поиск строк, не содержащих ничего между началом и концом строки, а благодаря восклицательному знаку на печать выводятся лишь строки, которые не соответствуют этому шаблону. Символ точка Точка используется для поиска любого одиночного символа, за исключением символа перевода строки. Передадим такому регулярному выражению файл myfile, содержимое которого приведено ниже
$ awk '/.st/{print $0}' myfile Использование точки в регулярных выражениях

114 Как видно по выведенным данным, шаблону соответствуют лишь первые две строки из файла, так как они содержат последовательность символов «st», предварённую ещё одним символом, в то время как третья строка подходящей последовательности не содержит, а в четвёртой она есть, но находится в самом начале строки. Классы символов Точка соответствует любому одиночному символу, но что если нужно более гибко ограничить набор искомых символов В подобной ситуации можно воспользоваться классами символов. Благодаря такому подходу можно организовать поиск любого символа из заданного набора. Для описания класса символов используются квадратные скобки — []:
$ awk '/[oi]th/{print $0}' myfile Описание класса символов в регулярном выражении Тут мы ищем последовательность символов «th», перед которой есть символ «o» или символ «i». Классы оказываются очень кстати, если выполняется поиск слов, которые могут начинаться как с прописной, таки со строчной буквы
$ echo "this is a test" | awk '/[Tt]his is a test/{print $0}'
$ echo "This is a test" | awk '/[Tt]his is a test/{print $0}' Поиск слов, которые могут начинаться со строчной или прописной буквы Классы символов не ограничены буквами. Тут можно использовать и другие символы. Нельзя заранее сказать, в какой ситуации понадобятся классы — всё зависит от решаемой задачи. Отрицание классов символов Классы символов можно использовать и для решения задачи, обратной описанной выше. А именно, вместо поиска символов, входящих в класс, можно организовать поиск всего, что в класс не входит. Для того, чтобы добиться такого поведения регулярного выражения, перед списком символов класса нужно поместить знак ^. Выглядит это так
$ awk '/[^oi]th/{print $0}' myfile

115 Поиск символов, не входящих в класс В данном случае будут найдены последовательности символов «th», перед которыми нет ни «o», ни
«i». Диапазоны символов В символьных классах можно описывать диапазоны символов, используя тире
$ awk '/[e-p]st/{print $0}' myfile Описание диапазона символов в символьном классе В данном примере регулярное выражение реагирует на последовательность символов «st», перед которой находится любой символ, расположенный, в алфавитном порядке, между символами «e» и
«p». Диапазоны можно создавать и из чисел
$ echo "123" | awk '/[0-9][0-9][0-9]/'
$ echo "12a" | awk '/[0-9][0-9][0-9]/' Регулярное выражение для поиска трёх любых чисел В класс символов могут входить несколько диапазонов
$ awk '/[a-fm-z]st/{print $0}' myfile

116 Класс символов, состоящий из нескольких диапазонов Данное регулярное выражение найдёт все последовательности «st», перед которыми есть символы из диапазонов a-f и m-z. Специальные классы символов В BRE имеются специальные классы символов, которые можно использовать при написании регулярных выражений
● [[:alpha:]] — соответствует любому алфавитному символу, записанному в верхнем или нижнем регистре.
● [[:alnum:]] — соответствует любому алфавитно-цифровому символу, а именно — символам в диапазонах 0-9, A-Z, a-z.
● [[:blank:]] — соответствует пробелу и знаку табуляции.
● [[:digit:]] — любой цифровой символ от 0 до 9.
● [[:upper:]] — алфавитные символы в верхнем регистре — A-Z.
● [[:lower:]] — алфавитные символы в нижнем регистре — a-z.
● [[:print:]] — соответствует любому печатаемому символу.
● [[:punct:]] — соответствует знакам препинания.
● [[:space:]] — пробельные символы, в частности — пробел, знак табуляции, символы NL, FF, VT, CR. Использовать специальные классы в шаблонах можно так
$ echo "abc" | awk '/[[:alpha:]]/{print $0}'
$ echo "abc" | awk '/[[:digit:]]/{print $0}'
$ echo "abc123" | awk '/[[:digit:]]/{print $0}' Специальные классы символов в регулярных выражениях Символ «звёздочка» Если в шаблоне после символа поместить звёздочку, это будет означать, что регулярное выражение сработает, если символ появляется в строке любое количество раз — включая и ситуацию, когда символ в строке отсутствует.
$ echo "test" | awk '/tes*t/{print $0}'

117
$ echo "tessst" | awk '/tes*t/{print $0}' Использование символа * в регулярных выражениях Этот шаблонный символ обычно используют для работы со словами, в которых постоянно встречаются опечатки, или для слов, допускающих разные варианты корректного написания
$ echo "I like green color" | awk '/colou*r/{print $0}'
$ echo "I like green colour " | awk '/colou*r/{print $0}' Поиск слова, имеющего разные варианты написания В этом примере одно и тоже регулярное выражение реагирует и на слово «color», и на слово «colour». Это так благодаря тому, что символ «u», после которого стоит звёздочка, может либо отсутствовать, либо встречаться несколько раз подряд.
Ещё одна полезная возможность, вытекающая из особенностей символа звёздочки, заключается в комбинировании его сточкой. Такая комбинация позволяет регулярному выражению реагировать на любое количество любых символов
$ awk '/this.*test/{print $0}' myfile Шаблон, реагирующий на любое количество любых символов В данном случае неважно сколько и каких символов находится между словами «this» и «test».
Звёздочку можно использовать и с классами символов
$ echo "st" | awk '/s[ae]*t/{print $0}'
$ echo "sat" | awk '/s[ae]*t/{print $0}'
$ echo "set" | awk '/s[ae]*t/{print $0}'

118 Использование звёздочки с классами символов Во всех трёх примерах регулярное выражение срабатывает, так как звёздочка после класса символов означает, что если будет найдено любое количество символов «a» или «e», а также если их найти не удастся, строка будет соответствовать заданному шаблону. Регулярные выражения POSIX ERE Шаблоны стандарта POSIX ERE, которые поддерживают некоторые утилиты Linux, могут содержать дополнительные символы. Как уже было сказано, awk поддерживает этот стандарта вот sed — нет. Тут мы рассмотрим наиболее часто используемые в шаблонах символы, которые пригодятся вам при создании собственных регулярных выражений. Вопросительный знак Вопросительный знак указывает на то, что предшествующий символ может встретиться в тексте один разили не встретиться вовсе. Этот символ — один из метасимволов повторений. Вот несколько примеров
$ echo "tet" | awk '/tes?t/{print $0}'
$ echo "test" | awk '/tes?t/{print $0}'
$ echo "tesst" | awk '/tes?t/{print $0}' Вопросительный знак в регулярных выражениях Как видно, в третьем случае буква «s» встречается дважды, поэтому на слово «tesst» регулярное выражение не реагирует. Вопросительный знак можно использовать и с классами символов
$ echo "tst" | awk '/t[ae]?st/{print $0}'
$ echo "test" | awk '/t[ae]?st/{print $0}'
$ echo "tast" | awk '/t[ae]?st/{print $0}'
$ echo "taest" | awk '/t[ae]?st/{print $0}'
$ echo "teest" | awk '/t[ae]?st/{print $0}'

119 Вопросительный знаки классы символов Если символов из класса в строке нет, или один из них встречается один раз, регулярное выражение срабатывает, однако стоит в слове появиться двум символами система уже не находит в тексте соответствия шаблону. Символ плюс Символ плюс в шаблоне указывает на то, что регулярное выражение обнаружит искомое в том случае, если предшествующий символ встретится в тексте один или более раз. При этом на отсутствие символа такая конструкция реагировать не будет
$ echo "test" | awk '/te+st/{print $0}'
$ echo "teest" | awk '/te+st/{print $0}'
$ echo "tst" | awk '/te+st/{print $0}' Символ плюс в регулярных выражениях В данном примере, если символа «e» в слове нет, движок регулярных выражений не найдёт в тексте соответствий шаблону. Символ плюс работает и с классами символов — этим он похож назв здочку и вопросительный знак
$ echo "tst" | awk '/t[ae]+st/{print $0}'
$ echo "test" | awk '/t[ae]+st/{print $0}'
$ echo "teast" | awk '/t[ae]+st/{print $0}'
$ echo "teeast" | awk '/t[ae]+st/{print $0}' Знак плюс и классы символов В данном случае если в строке имеется любой символ из класса, текст будет сочтён соответствующим шаблону.

120 Фигурные скобки Фигурные скобки, которыми можно пользоваться в шаблонах, похожи на символы, рассмотренные выше, но они позволяют точнее задавать необходимое число вхождений предшествующего им символа. Указывать ограничение можно в двух форматах
● n — число, задающее точное число искомых вхождений
● n, m — два числа, которые трактуются так как минимум n разно не больше чем m». Вот примеры первого варианта
$ echo "tst" | awk '/te{1}st/{print $0}'
$ echo "test" | awk '/te{1}st/{print $0}' Фигурные скобки в шаблонах, поиск точного числа вхождений В старых версиях awk нужно было использовать ключ командной строки --re-interval для того, чтобы программа распознавала интервалы в регулярных выражениях, нов новых версиях этого делать ненужно echo "teeest" | awk '/te{1,2}st/{print $0}' Интервал, заданный в фигурных скобках В данном примере символ «e» должен встретиться в строке 1 или 2 раза, тогда регулярное выражение отреагирует на текст. Фигурные скобки можно применять и с классами символов. Тут действуют уже знакомые вам принципы
$ echo "tst" | awk '/t[ae]{1,2}st/{print $0}'
$ echo "test" | awk '/t[ae]{1,2}st/{print $0}'
$ echo "teest" | awk '/t[ae]{1,2}st/{print $0}'
$ echo "teeast" | awk '/t[ae]{1,2}st/{print $0}'

121 Фигурные скобки и классы символов Шаблон отреагирует на текст в том случае, если в нём один или два раза встретится символ «a» или символ «e». Символ логического или Символ | — вертикальная черта, означает в регулярных выражениях логическое или. Обрабатывая регулярное выражение, содержащее несколько фрагментов, разделённых таким знаком, движок сочтёт анализируемый текст подходящим в том случае, если он будет соответствовать любому из фрагментов. Вот пример
$ echo "This is a test" | awk '/test|exam/{print $0}'
$ echo "This is an exam" | awk '/test|exam/{print $0}'
$ echo "This is something else" | awk '/test|exam/{print $0}' Логическое или в регулярных выражениях В данном примере регулярное выражение настроено на поиск в тексте словили. Обратите внимание на то, что между фрагментами шаблона и разделяющим их символом | не должно быть пробелов. Группировка фрагментов регулярных выражений Фрагменты регулярных выражений можно группировать, пользуясь круглыми скобками. Если сгруппировать некую последовательность символов, она будет восприниматься системой как обычный символ. То есть, например, к ней можно будет применить метасимволы повторений. Вот как это выглядит
$ echo "Like" | awk '/Like(Geeks)?/{print $0}'
$ echo "LikeGeeks" | awk '/Like(Geeks)?/{print $0}' Группировка фрагментов регулярных выражений

122 В данных примерах слово «Geeks» заключено в круглые скобки, после этой конструкции идёт знак вопроса. Напомним, что вопросительный знак означает «0 или 1 повторение, в результате регулярное выражение отреагирует и на строку «Like», и на строку «LikeGeeks». Практические примеры После того, как мы разобрали основы регулярных выражений, пришло время сделать сих помощью что-нибудь полезное.
1   2   3   4   5   6


написать администратору сайта