Назад в раздел
 
sed  и  awk. Учебное пособие.
sed и  awk 
 
 
		       sed  и  awk 
		    (учебное пособие) 
 
(с) А.Соловьев 
 
 
		I. ПОТОКОВЫЙ РЕДАКТОР sed 
 
     Команда имеет формат: 
 
	  sed [	-n ] [ -e script ] [ -f	sfile ]	[ files	] 
 
     Команда  копирует файлы (по умолчанию со стандартного входа) 
на  стандартный выход, редактирует их в соответствии со своими(!) 
командами,  размещенными в "script" (в командном файле или строке 
редактора  [а  не shell!]). По флагу "-f" берет берет файл команд 
из  файла  "sfile";  Если  есть только опция "-e script", то флаг 
"-e"  можно  опустить. Флаг "-n" подавляет вывод (происходящий по 
умолчанию). "script" состоит из команд редактирования, по одной в 
строке, имеющих формат: 
 
	       [ addr [ , addr ] ] cmd [ args ] 
 
     "sed"  циклически  преобразует входные строки в выходные. 
     Адреса  "[  addr [ , addr ] ]" - это либо номера строк, либо 
последняя  строка (символ "$"), либо регулярные выражения в стиле 
редактора "ed": 
     -    ""   используется   в   многострочных   командах   для 
экранирования продолжения строки. 
     -  "." совпадает с любым символом. 
     - Если  адреса  не  указаны  -  просматриваются все  входные 
строки. 
     - Если один адрес, то выбираются совпадающие строки. 
     - Если  заданы  два  адреса,  выбираются  строки в  заданном 
интервале. 
     -  "!cmd"  выполняется  команда "cmd", для строк, которые не 
были выбраны по адресам. 
 
     Для следующих (основных) функций (команд) максимальное число 
допустимых адресов указано в скобках. 
 
     (1)a 
     text  Добавляет text после указанной строки 
 
Команда: 
who 
Результат: 
root     tty1         Mar 13 17:23 
mas      tty2         Mar 13 18:50 
sae      tty6         Mar 13 17:24 
sae      tty5         Mar 13 17:24 
 
Пример: 
who | sed  '2a 
новая строка 
' 
 
Результат: 
root     tty1         Mar 13 17:23 
mas      tty2         Mar 13 18:50 
новая строка 
sae      tty6         Mar 13 17:24 
sae      tty5         Mar 13 17:24 
 
 
     (2)b label 
     Осуществляет  переход  к  команде  ("cmd")  "label:cmd" Если 
метка ("label") отсутствует, то переход на конец командного файла. 
 
Пример: 
who | sed  '2a 
новая строка 
b lb 
2d 
: lb 3d 
' 
 
Результат: 
root     tty1         Mar 13 17:23 
mas      tty2         Mar 13 18:50 
новая строка 
sae      tty5         Mar 13 17:24 
 
 
     (2)c 
     text  Удаляет выбранные строки и заменяет их на "text'. 
 
Пример: 
who | sed '/sae/ c 
cтрока замены 
' 
 
Результат: 
root     tty1         Mar 13 17:23 
mas      tty2         Mar 13 18:50 
строка замены 
строка замены 
 
     (2)d  Удаляет найденные строки 
 
Пример: 
who | sed '2,4d' 
 
Результат: 
root     tty1         Mar 13 17:23 
 
	  (1)i 
	  text      Вставляет "text" на место выбранной строки. 
		    (сравните с "a") 
Пример: 
who | sed  '2i 
новая строка 
' 
 
Результат: 
root     tty1         Mar 13 17:23 
новая строка 
mas      tty2         Mar 13 18:50 
sae      tty6         Mar 13 17:24 
sae      tty5         Mar 13 17:24 
 
 
 
     (2)p  Выводит найденные строки (используется с флагом "-n"). 
 
     (1)q  Выходит из "sed". 
 
     (2)r rfile 
      Читает файл  "rfile" и выдает на выход. 
 
     (2)s/reg_expr/rpl/flags 
     Заменяет  регулярное  выражение "reg_expr" на "rpl" с учетом 
флагов "flags": 
		    g - глобально (по всей строке) 
		    p - выводить замены 
		    w wfile - сохранять заменяемое в "wfile". 
 
Пример: 
who | sed  's/t/T/' 
echo 
who | sed  's/t/T/g' 
 
Результат: 
rooT     tty1         Mar 13 17:23 
mas      Tty2         Mar 13 18:50 
sae      Tty6         Mar 13 17:24 
sae      Tty5         Mar 13 17:24 
 
rooT     TTy1         Mar 13 17:23 
mas      TTy2         Mar 13 18:50 
sae      TTy6         Mar 13 17:24 
sae      TTy5         Mar 13 17:24 
 
     (2)y/str1/str2/ 
     Заменяет все вхождения символов "str1" соответсвующими символами 
"str2". Длины строк должны быть одинаковыми. 
 
Пример: 
who | sed  'y/sae/SAE/' 
 
Результат: 
root     tty1         MAr 13 17:23 
mAS      tty2         MAr 13 18:50 
SAE      tty6         MAr 13 17:24 
SAE      tty5         MAr 13 17:24 
 
 
     (2)! cmd  Команда(ы) "cmd" применяются к невыбранным строкам. 
 
Пример: 
who | sed '2,4!d' 
 
Результат: 
mas      tty2         Mar 13 18:50 
sae      tty6         Mar 13 17:24 
sae      tty5         Mar 13 17:24 
 
	  (1)=  Выдает номера строк. 
 
Пример: 
who | sed = 
 
Результат: 
1 
root     tty1         Mar 13 17:23 
2 
mas      tty2         Mar 13 18:50 
3 
sae      tty6         Mar 13 17:24 
4 
sae      tty5         Mar 13 17:24 
 
	  (2){ } Скобки группируют команды. 
 
 
		-------------"-------------- 
 
 
		 II. ЯЗЫК ОБРАБОТКИ ШАБЛОНОВ awk 
		     (Aho, Weinberg, Kernigan) 
 
     awk  -  команда контекстного поиска и преобразования текста. 
Она  -  фильтр.  Ее  можно  рассматривать  как  оболочку  "awk" в 
оболочке "shell". 
 
		   1. СТРУКТУРА awk-ПРОГРАММЫ 
 
     Программа состоит из операторов (правил), имеющих вид: 
 
шаблон {действие} 
шаблон {действие} 
. . . 
 
     Частные случаи: 
 
{действие}   - когда действие выполняется для всех строк. 
шаблон       - когда выводятся строки с данным шаблоном. 
 
 
     Действие может состоять из последовательности операторов, 
разделяемой ";" или переводом строки или закрывающей скобкой. 
 
     Возможны комментарии (как в shell "#........."). 
 
     Пример: 
     Для  дальнейших  примеров  возьмем входной  файл  "f-awk" 
( фамилия инициалы год-приема-на-работу возраст ): 
 
Иванов И.И.   1980  50 
Петров А.В.   1979  40 
Сидоров С.К.  1979  40 
Хведоров И.Х. 1970  60 
 
awk '{print}' f-awk       # выдает весь текст; 
echo 
awk '/до/ {print}' f-awk  # выдает строки, где есть "до". 
echo 
awk '/до/ {}' f-awk       # выдает строки, где есть "до" 
echo 
awk '/до/ {print("Привет!")}' f-awk 
 
Результат: 
Иванов И.И.   1980  50 
Петров А.В.   1979  40 
Сидоров С.К.  1979  40 
Хведоров И.Х. 1970  60 
 
Сидоров С.К.  1979  40 
Хведоров И.Х. 1970  60 
 
Сидоров С.К.  1979  40 
Хведоров И.Х. 1970  60 
 
Привет! 
Привет! 
 
     Существует   два   оператора   специального  вида  ("BEGIN"- 
начальные установки и "END" - "последействия"): 
 
BEGIN {действие} 
     шаблон {действие} 
     шаблон {действие} 
     . . . 
END   {действие} 
 
 
			2. ВЫЗОВ awk 
 
     Возможны два основных варианта: 
 
1)   awk [-Fc] 'prog.awk' [files] 
 
     Это   простейший  случай,  когда  программа  (заключенная  в 
кавычки " ' ") находится в теле команды, 
     "-Fc" - флаг, меняющий стандартный разделитель полей на "c" 
     "file"  - имя файла исходных данных, при его отсутствии - со 
стандартного входа. (Этот формат исползован в начальных примерах). 
 
cat f-awk | awk '/до/ {print}' 
 
     и 
 
awk '/до/ {print}' < f-awk 
 
     дают результат, аналогичный 
 
awk '/до/ {print}'  f-awk 
 
     Для демонстрации действия флага "-Fc" рассмотрим вызовы: 
 
awk  '/до/ {print($2)}'  f-awk 
awk -F0 '/до/ {print($2)}'  f-awk 
 
     На экран будет выведено: 
 
С.К. 
И.Х. 
 
  6 
 
     Первая   команда   "awk"   выведет  вторые  поля  (благодаря 
позиционной  переменной  "$2")  строк,  содержащие "до". (Кстати, 
позиционная переменная "$0" соответсвует всей строке). 
     Во   втором   случае,   благодаря   флагу  "-F"  стандартные 
разделители заменены на символ "0", т.е. теперь выбранные строки 
воспринимаются,  как разбитые на следующие поля: 
 
Сидоров С.К.  1979  40 
---------------------^-------------------- 
1-е поле               2-е поле (пусто) 
 
Хведоров И.Х. 1970  60 
-----------------^---^-------------------- 
1-е поле          2-е  3-е поле (пусто) 
 
 
2)   awk [-Fc] -f prog.awk  [files] 
 
     Флаг  "-f"  говорит  о  том, что awk-программу надо брать из 
файла, имя которого указано следом (имя может быть произвольным и 
расширение   ".awk"   добавлено   здесь  просто  из  эстетических 
соображений). 
 
		3. awk-ПЕРЕМЕННЫЕ И ВЫРАЖЕНИЯ 
 
     В    языке    awk    выделяются   две   группы   переменных: 
предопределенные и декларированные в программе. Исходные значения 
предопределенных переменных устанавливаются интерпретатором awk в 
процессе запуска и выполнения awk-программы. 
К предопределенным относятся:                     Умолчания: 
NR        номер текущей строки; 
NF        число полей в текущей строке; 
RS        разделитель строк на вводе;              " " 
FS        разделитель полей на вводе;      пробел и/или табуляция 
ORS       разделитель строк на выводе;              RS 
OFS       разделитель полей на выводе;              FS 
OFMT      формат вывода чиcл;                     "%.6g" 
FILENAME  имя входного файла. 
 
     Прочим  переменным  пользователь может присваивать начальные 
значения.   По   умолчанию  "0"  или  пустая  строка  (что  здесь 
равнозначно!). 
     Типы переменных: 
     - позиционные, 
     - числа с плавающей точкой, 
     - строка символов, 
     - массив. 
 
     Интерпретатор  awk  рассматривает  переменную как строковую, 
пока не возникает необходимость выполнить операции: 
     - если пробел (конкатенация), то строки; 
     - если "+", то числа с плавающей точкой. 
 
     Примеры: 
 
awk '{a = $3 $4; print a}' f-awk 
awk '{a = $3+$4; print a}' f-awk 
 
     Результат: 
198050 
197940 
197940 
197060 
2030 
2019 
2019 
2030 
 
awk '{} 
END {a = 2 + 2        ; print a}' < f-awk 
awk '{} 
END {a = 2 + "2"      ; print a}' < f-awk 
awk '{} 
END {a = 2 + "два"    ; print a}' < f-awk 
awk '{} 
END {a = "два"+"два"  ; print a}' < f-awk 
awk '{} 
END {a = 2.2 + 2.000  ; print a}' < f-awk 
 
     Результат: 
4 
4 
2 
0 
4.2 
 
     Массив  не  об'является,  а  начинае  существовать  в момент 
первого  использования. Индекс массива - любое ненулевое значение 
или  строка.  Массивы  ассоциативные,  т.е.  не  по  вычисляемому 
индексу, а по совпадению содержания, например: 
     day [Jan][31] = Mon 
     day [Feb][01] = Tue 
     day [Feb][02] = Wed 
 
     Массивы  удобно  использовать  при  суммированиях,  например 
записи выплат имеют вид (файл "p-1"): 
John  100 
Mary  200 
Mary  200 
John  100 
John  300 
 
awk '{sum[$1] += $2; print $1 sum[$1]} ' < p-1 
 
     Результат (поименный нарастающий итог): 
John100 
Mary200 
Mary400 
John200 
John500 
 
     Операции как в Си: 
=, +=, -=, *=, /=, %=, +, /, %, ++, --. 
 
     Сравнения чисел, если оба числа, иначе - строк: 
 
 
     Логические операции: 
!, ||, && 
 
Операция "пробел" - конкатенация. 
 
 
		4. ПРИМЕРЫ awk-ПРОГРАММ 
 
1) awk '{print ($2, $3)}' f-awk 
 
     Результат: 
И.И. 1980 
А.В. 1979 
С.К. 1979 
И.Х. 1970 
 
2) awk '/е/ {print ($2, $3)}' f-awk 
 
     Результат: 
А.В. 1979 
И.Х. 1970 
 
3) awk '/е/ {print ($1, 2000 - $3)}' f-awk 
 
     Результат: 
Петров 21 
Хведоров 30 
 
4) awk '{ s = s + $4} 
   END {print ("Суммарный возраст:" s) 
	print ("Средний   возраст:" s/NR)}' f-awk 
 
     Результат: 
Суммарный возраст:190 
Средний   возраст:47.5 
 
5) awk '{ s += $4 } 
	{print("NR="NR, "NF="NF)} 
   END {print ("FILENAME=" FILENAME) 
	print ("Значение позиционной переменной" $4 ""пусто"  
после окончания просмотра)") 
	print ("Суммарный возраст:" s) 
	print ("Средний   возраст:" s/NR)}' f-awk 
 
     Результат: 
NR=1 NF=4 
NR=2 NF=4 
NR=3 NF=4 
NR=4 NF=4 
FILENAME=f-awk 
Значение позиционной переменной"пусто" после окончания просмотра) 
Суммарный возраст:190 
Средний   возраст:47.5 
 
 
		      5. СЕЛЕКТОРЫ 
 
     Здесь  "селектор"  следует  понимать, как расширение понятия 
"шаблон",  поскольку там где в структуре команды указан шаблон, в 
общем случае может стоять любой селектор. 
     ЗАМЕЧАНИЕ.  Открывающая  скобка  действия  "{" должна быть в 
строке селектора. 
     В качестве селектора может быть: 
     1) выражение; 
     2) шаблон; 
     3) их комбинация. 
 
     Соответсвующие примеры: 
     1) $3 != $4 && $3 > 1970 
	$3 % 2 == 1 
	$1=="Иванов" - кавычки, чтобы воспринималось, как строка. 
 
     2) /ab/ отлично от /a b/, / ab/ и /ab / 
	Nполя ^шаблон   - по совпадению 
	Nполя !^шаблон  - по несовпадению 
 
	Пример: 
awk '$3~0 {print} ' < f-awk 
echo 
awk '$3!~0 {print} ' < f-awk 
 
Иванов И.И.   1980  50 
Хведоров И.Х. 1970  60 
 
Петров А.В.   1979  40 
Сидоров С.К.  1979  40 
 
     3)   Шаблон   может   формировать   множество  образцов  или 
указывать, в каком месте поля искать: 
     /^a/  - поле начинается с "a" 
     /a$/  - поле кончается "a" 
     +    - экранирует оператор 
    [abc]  - любой из символов "a", "b" и "c" 
    [a-р]  - любой символ диапазона 
     *     - 0 или больше вхождений регулярного выражения 
     +     - 1 или больше вхождений регулярного выражения 
     ?     - 0 или 1 вхождение регулярного выражения 
    ab|cd  -  "ab" или "cd" 
 
     Примеры сочетаний: 
awk ' $3~/(7[0-9])$/ {print} ' f-awk 
 
     Результат: 
Петров А.В.   1979  40 
Сидоров С.К.  1979  40 
Хведоров И.Х. 1970  60 
 
     То  есть  в  третьем  поле  выделить 70-е годы (7 и еще одна 
цифра от конца поля). 
 
		      6. ЕЩЕ ПРИМЕРЫ 
 
 
1) awk '$1=="Иванов" {print} ' f-awk 
 
     Результат: 
Иванов И.И.   1980  50 
 
2) awk '$4/2==30  {print} ' f-awk 
 
     Результат: 
Хведоров И.Х. 1970  60 
 
3) awk '$3 != $4 && $3 > 1970  {print} ' f-awk 
 
     Результат: 
Иванов И.И.   1980  50 
Петров А.В.   1979  40 
Сидоров С.К.  1979  40 
 
4) awk '$1~/нов$/ {print} ' f-awk 
 
     Результат: 
Иванов И.И.   1980  50 
 
5) awk '/^Ив|дор/  {print} ' f-awk 
 
     Результат: 
Иванов И.И.   1980  50 
Сидоров С.К.  1979  40 
Хведоров И.Х. 1970  60 
 
6) awk '/1980/,/1979/ {print} ' f-awk 
 
     Результат: 
Иванов И.И.   1980  50 
Петров А.В.   1979  40 
 
 
			7. ДЕЙСТВИЯ 
 
     В awk возможны следующие действия: 
     1) присваивания выражений; 
     2) операторы управления 
     3) операторы вывода; 
     4) встроенные функции. 
 
		    ОПЕРАТОРЫ УПРАВЛЕНИЯ 
 
     Простейшие операторы 
 
exit  -     завершить выполнение программы; 
next  -     перейти к следующей строке, 
	    управление на начало awk-программы; 
break -     выход из цикла; 
continue -  переход к следующей итерации; 
 
     Структурные операторы 
 
if (условие) {операторы} [else {операторы}] 
while (условие) {операторы} 
for (выражение; условие; выражение) {операторы} 
for (индекс  in  имя_массива) {операторы} 
 
     Структурные  операторы  в  значительной  степени  аналогичны 
соответсвующим операторам Си. 
     В  последнем  случае  для  каждого индекса выполняется блок. 
Текстовые индексы рассматирваются в лексикографическом порядке. 
 
     Примеры 
 
1) awk ' $4~/40/ {if($30; --k) {print $k} 
     {print RS} 
   } ' f-awk | 
   sed 's/^ //' 
 
     Результат: 
50 1980 И.И. Иванов  
40 1979 А.В. Петров  
40 1979 С.К. Сидоров  
60 1970 И.Х. Хведоров  
 
     Здесь,   кроме  изменения  очередности  полей  в  строке  на 
противоположное   (что   делает   цикл   "for"),   предварительно 
устанавливается  выходной  разделитель  - пробел и весь результат 
предварительно  выдается  в  одну строку, поэтому после обработки 
каждой  строки  выдается команда "print RS" для перевода выходной 
строки.  Редактор  "sed"  подключен  через конвейер, чтобы убрать 
возможные пробелы в начале строки. 
     Существенная деталь. Если запустить лишь базовую структуру 
 
awk '{ for(k=NF; k>0; --k) {print $k}}' f-awk 
 
     то  все  поля  исходной таблицы с изменениями порядка внутри 
прежних строк получим вытянутыми в один столбец переводом строки: 
 
50 
1980 
И.И. 
Иванов 
40 
1979 
А.В. 
Петров 
40 
1979 
С.К. 
Сидоров 
60 
1970 
И.Х. 
Хведоров 
 
     Однако,  если поставим ";" сразу после условия, т.е. сделаем 
пустое тело цикла, за пределы которого вынесен "print $k" 
 
awk '{ for(k=NF; k>0; --k); {print $k}}' f-awk 
 
     то получим исходную таблицу 
 
Иванов И.И.   1980  50 
Петров А.В.   1979  40 
Сидоров С.К.  1979  40 
Хведоров И.Х. 1970  60 
 
     поскольку  "$k"  после  выхода из цикла будет иметь значение 
"0", а "$0" - соответсвует всей строке в качестве значения(!), то 
"print $k" будет после каждого цикла печатать полные строки. 
 
 
		 8. ВВОД И ВЫВОД ДАННЫХ 
 
     В  общем  случае  в команде awk может быть указано несколько 
файлов. 
     Напомним форматы вызова команды: 
 
awk [-Fc] 'prog.awk' [file ...] 
awk [-Fc] -f prog.awk  [file ...] 
			      ^ 
     Файлы обрабатываются последовательно в указанном порядке. 
     Это  можно  использовать  для  "настройки"  awk  команды при 
обработке последующих файлов. 
 
     Пусть файл "f0" имеет вид: 
 
60 Сидоров 
 
     А файл awk-программы "prim.awk" имеет вид: 
 
FILENAME == "f0" {            # если просматривается файл "f0" 
		  w1 = $2     # присваиваются значения переменным 
		  w2 = $1     # w1 - Сидоров, w2 - 60 
		 } 
$1 == w1         { print ("фамилия: "$1)} # означенные переменные 
$4 == w2         { print ("годы: " $4)}   # используются в 
					  # селекторах 
 
     Тогда при вызове команды 
 
awk -f prim.awk  f0  f-awk 
 
     Результат: 
 
фамилия: Сидоров 
годы: 60 
 
     То  есть  второе  поле  файла  "f0" дает значение переменной 
"w1",  а  первое - "w2". Эти переменные используются в селекторах 
при обработке файла "f-awk". 
 
     Изменим программу в файле "f-awk": 
 
FILENAME == "f0" { 
		    w1 = $2 
		    w2 = $1 
		    next 
		 } 
		 { print ("фамилия: "$1); next} 
$4 == w2         { print ("годы: " $4)} 
 
     Результат: 
фамилия: Иванов 
фамилия: Петров 
фамилия: Сидоров 
фамилия: Хведоров 
 
     Если  исключить  первый оператор "next", то в выходном файле 
появится дополнительно первая строка: 
 
фамилия: 60 
 
     поскольку выбирается снова первое поле в певом файле ("f0"). 
     Если исключить и второй "next", то в выходном файле появится 
дополнительно последняя строка: 
 
годы: 60 
 
     которая  ранее  не  выводилась,  так  как  в  предшествующий 
оператор  "  {  print  ("фамилия:  "$1)}"  заканчивал  работу  на 
ПОСЛЕДНЕЙ   строке   файла   "f-awk",  поэтому  "next"  пропускал 
последующую командную строку 
$4 == w2         { print ("годы: " $4)} 
 
     И еще одна модификация в связи с вводом данных с терминала. 
Вызов команды будет: 
 
awk -f prim.awk  f0  f-awk 
 
А файл "prim.awk" примет вид: 
 
BEGIN { print ("Введите годы и фамилию: ")} 
FILENAME == "-" { 
		  w1 = $2 
		  w2 = $1 
		next 
		} 
$1 == w1        { print ("фамилия: "$1); next} 
$4 == w2        { print ("годы: " $4)} 
 
 
		  9. ВСТРОЕННЫЕ ФУНКЦИИ 
 
     Встроенные функции: 
     sin (expr)         синус  expr 
     cos (expr)         косинус expr 
     exp (expr)         возведение в степень expr 
     log (expr)         натуральный логорифм expr 
     sqrt (expr)        извлечение корня expr 
     int (expr)         целая часть числа 
     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=" "); 
			функция возвращает число полей. 
 
     Примеры. 
 
1) awk '     BEGIN {FS = "."; a=0} 
   length ($1) > 8 {print (length ($1), $0); 
		    a++ 
		   } 
	       END {print ("Найдено строк: " a) }' f-awk 
 
     Результат: 
9 Сидоров С.К.  1979  40 
10 Хведоров И.Х. 1970  60 
Найдено строк: 2 
 
     Здест  поля  разделяются по ".", выбираются строки у которых 
длина  первого  поля  больше  8-ми,  и  их  длина  "length  ($1)" 
печатается перед строкой "$0". 
 
2) awk '{i=split($0, Name, "."); 
	 for (j=1; j 
 |   
 | 
  | 
 |