Awk — a pattern scanning and processing language 

                                 SED — Stream EDitor

AWK & SED

Оглавление страницы



Escape–последовательности

Команда printf

Преобразование символов

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

Передача переменных утилите awk

Файлы сценариев

Использование переменной FS в сценариях awk

Передача переменных сценариям awk

Массивы

Статические массивы

                     SED

Работа с редактором sed

Чтение и обработка данных в sed

Вызов редактора sed

Сохранение выходных данных

Синтаксис команд

Правила отбора строк в редакторе sed:

Основные команды редактирования

Регулярные выражения

Вывод строк (команда p)

Отображение строки по номеру

Поиск специальных символов

Поиск первой строки

Вывод номеров строк (команда =)

Отображение строк из заданного диапазона

Поиск строк, соответствующих шаблону

Поиск пo шаблону и номеру строки

Поиск последней строки

Отображение всего файла

Добавление текста (команда а)

Создание файла сценария

Вставка текста (команда i)

Удаление текста (команда d)

Изменение текста (команда с)

Замена подстроки (команда s)

Ссылка на искомую подстроку с помощью метасимвола &

Чтение строк из файла (команда r)

Вывод строк в файл (команда w)

Досрочное завершение работы (команда q)

Отображение управляющих символов (команда l)

Обработка управляющих символов

Обработка отчетов

Добавление текста

Удаление начальной косой черты в путевом имени

Разбить строку на абзацы

Примеры операций в sed

                       AWK

Сценарии

Поля и записи

Тестовый файл

Сохранение выходных данных

Отображение всех записей

Отображение отдельных полей всех записей

Отображение заголовка отчета

Отображение резюме отчета

Обработка сообщений об ошибках

Ввод данных с клавиатуры

Метасимволы

Операторы

Операторы сравнения

Проверка на совпадение

Проверка на равенство

Проверки на несовпадение и неравенство

Проверка "меньше чем"

Проверка "меньше или равно"

Проверка "больше чем"

Логические операторы

Оператор логического И &&

Оператор логического ИЛИ ||

Операторы присваивания и арифметические операторы

Создание локальных переменных

Проверка значения поля

Изменение значения числового поля

Изменение значения текстового поля

Отображение только измененных записей

Создание нового поля

Суммирование столбцов

Суммирование размеров файлов

Встроенные переменные

Переменные NF, NR и FILENAME

Извлечение строк

Комбинировать строки с полями:

Подставить в команду:

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

Функция gsub()

Функция index()

Функция length()

Функция match()

Функция split()

Функция sub()

Функция substr()

Передача строк из интерпретатора shell утилите awk


Задачи обработки-фильтрации текста естественным и логичным образом являются приоритетными для администрирования *nix систем, кроме семейства команд обработки текста типа: grep, sort, tsort, uniq, past, join, tail и многих других, владение утилитами обработки текста как SED и AWK, необходимое условие профессионализма сисадминистратора, при помощи этих гибких и эффективных инструментов возможно создание как сложных скриптов так и однострочных команд (expressions) по не интерактивному редактированию проходящему через них потоку текста.   https://vds-admin.ru/sed-and-awk 

Поток данных (stream) в программировании — абстракция, используемая для чтения или записи файлов, сокетов и т. п. в единой манере.  Потоки являются удобным унифицированным программным интерфейсом для чтения или записи файлов (в том числе специальных и, в частности, связанных с устройствами), сокетов и передачи данных между процессами. Поддержка потоков включена в большинство языков программирования.

При создании любого процесса ядро создает три стандартных потока:

Поток ввода открыт на чтение, потоки вывода — на запись.  По умолчанию поток ввода связан с клавиатурой, потоки вывода — с дисплеем

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

Убедиться в том что это чистая правда можно выполнив в терминале следующую не хитрую команду:

$ ls -lah /proc/$$/fd/

total 0

dr-x------ 2   0 Jul 27 21:54 ./

dr-xr-xr-x 9   0 Jul 27 21:52 ../

lrwx------ 1  64 Jul 27 21:54 0 -> /dev/pts/0

lrwx------ 1  64 Jul 27 21:54 1 -> /dev/pts/0

lrwx------ 1  64 Jul 27 21:54 2 -> /dev/pts/0

lrwx------ 1  64 Jul 27 21:54 255 -> /dev/pts/0

$ ..зачем открыт файл с дескриптором 255 .... никто не знает, но это и не важно.

Так еще интересней:

$ ls -lah /proc/self/fd/

total 0

dr-x------ 2   0 Dec 17 18:40 ./

dr-xr-xr-x 9   0 Dec 17 18:40 ../

lrwx------ 1  64 Dec 17 18:40 0 -> /dev/pts/0

lrwx------ 1  64 Dec 17 18:40 1 -> /dev/pts/0

lrwx------ 1  64 Dec 17 18:40 2 -> /dev/pts/0

lr-x------ 1  64 Dec 17 18:40 3 -> /proc/144823/fd/


/proc/self@ является символической ссылкой на каталог, соответствующий текущему процессу,

$ ls -l /proc/self 

lrwxrwxrwx 1 root root 0 Dec 19  2022 /proc/self -> 9053/

, естественно содержимое ссылки меняется в зависимости от того, кто к ней обращается.

Тоже не плохой пример демонстрирующий как конструкция "herestring" передает строку в stdin, не создавая subshell:

$ ls -l <<< cd /proc/self/fd

total 0

lr-x------ 1 64 Dec 20 14:47 0 -> 'pipe:[198454]' #канал в stdin, и ни каких subshell

lrwx------ 1 64 Dec 20 14:47 1 -> /dev/pts/0

lrwx------ 1 64 Dec 20 14:47 2 -> /dev/pts/0

lr-x------ 1 64 Dec 20 14:47 3 -> /proc/47541/fd/

Б. Керниган, Д. Ритчи,  - Язык программирования С  << ----- ст. 230 PDF

N. Wirth Algorithm + Data structure = program               << ----- PDF почти филосовский трактат 

Данные  — абстракция некоторого фрагмента "видимого" мира.

Поток      — это источник или получатель данных связанный с диском или с каким-то другим внешним устройством. Библиотека поддерживает два вида потоков: текстовый и бинарный, хотя на некоторых системах, в частности в UNIXe, они не различаютсяПотоковый ввод-вывод 

Текстовый поток — это последовательность строк; каждая строка имеет от нуля или более символов и заканчивается управляющем символом '\n' - символом конца строки, либо перевода строки. Символы текста кодируются разными значениями байтов или их последовательностями. Информация о том, как именно эти символы должны располагаться на странице (форматироваться), тоже кодируется с помощью неотображаемых управляющих символов, типа конца строки  – ASCII 10 или символа табуляции – ASCII 9,11. В простейших случаях число управляющих кодов ограничивается 32-мя первыми значениями байта (или кода ASCII), а все остальные значения байта используются для кодирования информационных символов, текстовых символов. Именно такие файлы называются ASCII-файлами или "текстовыми". Структурированный текст - это текст ASCII (American Standard Code for Information Interchange), который состоит из полей со значениями и разделителей полей, которые обязательно присутствует в структуированном файле, в качестве разделителя полей могут использоваться различные символы, обычно это space – ASCII 32.  ASCII – не единственный, но самый простой возможный текстовый формат, так как он состоит только из текстовых символов и не содержат шрифтов, стилей, цветов и прочего

Примерами таких файлов могут служить файлы, создаваемые редакторами типа: ed, vi-vim, редактором mc и  прочих, естественно кроме создаваемых пользователем текстовых файлов существует масса системных, созданных и форматированных по тем же алгоритмам, потому наличие текстового редактора, как и утилит умеющих обрабатывать эти ASCII файлы, задача первоочередная для  *nix-систем, и как следствие по прежнему не утихает религиозная война между адептами vim и  emacs.

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


Поток, процесс соединяется с файлом или устройством посредством его открытия и идентифицируется системой посредствам (в конечном итоге) файловых дескрипторов, указанная связь разрывается путем закрытия потока, процесса. Открытие файла возвращает указатель на объект типа "FILE", который содержит всю информацию, необходимую для управления этим потоком.

Точнее так: В составе стандартной библиотеки C есть стандартная библиотека ввода-вывода, сокращенно именуемая stdio.

Указатели файлов: Процедуры стандартного ввода-вывода не работают непосредственно с файловыми дескрипторами, вместо этого каждая использует свой уникальный идентификатор, обычно называемый "указателем файла". В библиотеке C указатель файла ассоциируется с файловым дескриптором то есть отображается на него.  Указатель файла представлен как указатель на "определение типа" FILE, определяемый в <stdio.h>, Название FILE записывается прописными буквами по тому что изначально стандартный ввод вывод это "макрокоманда", По мере того как язык C развивался то и стандартный ввод-вывод был регламентирован как официальная часть языка, большинство методов были переписаны в виде обычных функций, а FILE стал "определением типа", но он так и продолжает записываться в верхнем регистре. В терминологии ввода-вывода открытый файл называется потоком данных.

При старте операционной системы создается что то порядка 12-и открытых файлов три из них зарезервированы для стандартных потоков ввода, вывода и ошибок

stdin(fd0), stdout(fd1) и stderr(fd2). Стандартный ввод-вывод 


Чтобы напечатать управляющие символы есть утилита cat c указанием опции -v, cat выводит эти символы в нотации "с крышкой'', т.е. они представляются сочетанием `^' и символа, соответствующего управляющему символу (^C - прервать),

Чтобы визуально отобразить конец строки в каждой строке, используйте опцию -E; она приведет к тому, что в конце каждой строки появится символ $.

Полезной является опция -T, которая выводит все табуляции в виде ^I.

Ключ -A комбинирует все три вышеуказанные опции - как если бы Вы указали опции с помощью -vET.


PS: Если в VIM поместить курсор на символ и нажать сочетание ga, можно увидеть его код в строке состояния. Например: ascii [+]:  <A>  65,  Hex  41,  Octal  101

VIM как hex/octal editor:

hex   :%!xxd    (вернуться :%!xxd -r)

octal :%!od

: входит в режим командной строки

% сопоставляет весь файл как диапазон,

! фильтрует этот диапазон с помощью внешней команды, 

xxd как и od , как и hd это внешниe  команды оболочки, после внесения изменений можно вернуться к тексту с помощью ключа -r (команды xxd), поэтому: :%!xxd -r

$ type xxd; xxd is /usr/bin/xxd

$ type od;  od is /usr/bin/od 

$ type hd; hd is /usr/bin/hd


Command Line Tools to dump files in hex,octal and bin formats

 SED: Stream EDitor — потоковый текстовый редактор как и AWK с полным на то основанием можно называть языком программирования, не интерактивный, построчный редактор текстовых файлов потокового типа, Sed получает входной поток данных или файл построчно, редактирует каждую строку согласно правилам, определённым в sed-скрипте, и затем выводит результат, текст принимается либо с устройства stdin, либо из текстового файла, после чего выполняются заданные операции над строками и выводится результат на устройство stdout или в файл. Резюмируя можно привести выдержку из отличной книги "Девид Тейнсли Linux и Unix Програмирование в Shell": Linux и UNIX: программирование в shell. Руководство разработчика.fb2 

"Отличительной особенностью редактора sed является то, что он позволяет модифицировать файлы в фоновом режиме. Задача пользователя сводится к тому, чтобы задать последовательность команд редактирования, а всю остальную работу выполнит сам редактор. Кроме того, sed допускает внесение всех изменений за один проход, а это превращает его в достаточно эффективный и, что важнее всего, быстродействующий инструмент редактирования текста, быстродействие достигается в следствии нескольких особенностей редактора, первая то, что он работает с "потоками" по сути средствами ядра операционной системы(и здесь надо вернуться  к понятию "поток"),

вторая это инвертированность(перевернутость) по отношению к тексту и набору команд редактирования, sed вначале загружает в себя набор команд, а затем применяет весь набор команд к каждой строке текста и по скольку одновременно в памяти находится только одна строка, sed может обрабатывать "произвольно большие" текстовые файлы — данные

AWK:  Язык обработки шаблонов с C-подобным синтаксисом, утилита AWK с полным на то основанием считается наиболее "продвинутым" средством по формированию отчетов и извлечению информации из больших текстовых файлов, что и неудивительно поскольку говоря про AWK на самом деле придется говорить не об одной из многочисленных утилит *nix систем, а о совершенно самостоятельном языке программирования, языке AWK, в чем собственно и скрывается не которая трудность в его или ее изучении. Примеров использования, шаблонов, скриптов, как и областей применения громадное множество, ниже, в большом количестве приводятся выдержки, цитаты и скрипты из выше упомянутой великолепной книги Дэвида Тейнсли, в книге сделан акцент на умение создавать эффективные одно-строчные команды и небольшие сценарии, выполняющие фильтрацию текстовых файлов по средствам AWK и SED, как раз то, что и необходимо в текущей работе по администрированию *nix систем.         

http://www.commandlinefu.com/commands/using/awk  — это место, где можно записать те жемчужины командной строки, к которым вы возвращаетесь снова и снова.

http://linuxgeeks.ru/awk.htm

http://www.lissyara.su/doc/programming/awk/      <<------------

http://citforum.ru/operating_systems/unixuser/gl10_1.shtml

https://www.opennet.ru/docs/RUS/bash_scripting

https://www.opennet.ru/base/dev/sed1line.txt.html   <<-----------Полезные одно-строчные скрипты sed

http://dbserv.pnpi.spb.ru/~shevel/Book/node67.html    <<------------

https://life-prog.ru/MAN AWK.html 

"Девид Тейнсли Linux и Unix Програмирование в Shell"    <<--------- PDF

"Девид Тейнсли Linux и Unix ........"         <<--------PDF (другой вариант, местами исправленный)


Aho Kernighan Weinberger:  "The AWK Programming Language"   <<--------- "первоисточник"


Уроки по Awk    <<--------------

AWK

Название утилиты AWK составлено из начальных букв фамилий разработчиков языка: Ахо (Aho), Вайнбергера (Weinberger) и Кернигана (Kernighan). Существуют также утилиты nawk и gawk, обладающие усовершенствованными возможностями обработки текста. Вызов утилиты awk возможен тремя способами:

awk [-F разделитель_полей] 'сценарий' входной_файл…

В одинарных кавычках (про которые ясно дело не стоит забывать) указывается список инструкций языка awk. Задавать разделитель полей с помощью опции -F не обязательно, так как по умолчанию утилита awk использует для этих целей пробел, и конечно при условии что в фильтруемом источнике

так-же использован пробел. Но, например, в файле /etc/passwd поля отделяются друг от друга двоеточием и в этом случае вызов утилиты выглядит так:

awk -F: 'сценарий' входной_файл…

awk -f файл_сценария входной_файл…

Опция -f свидетельствует о том, что инструкции awk содержатся в файле сценария. Утилита анализирует информацию, содержащуюся в одном или нескольких входных файлах.  

Сценарии

Сценарий awk — это набор инструкций, состоящих из шаблонов и связанных с ними процедур. Когда утилита просматривает записи входного файла, она проверяет, установлена ли опция -F или переменная FS (о чем поясняется позже), задающие разделители полей записи. По умолчанию в качестве разделителя принят пробел. При обнаружении символа новой строки прочитанная строка классифицируется как запись, и к ней применяются инструкции сценария. Процесс чтения записей продолжается до тех пор, пока не будет обнаружен признак конца файла. Возможны комментарии (как в shell "#.........").

В таблице ниже приведен образец входного файла и продемонстрировано, как утилита awk его анализирует. Утилита последовательно просматривает строки файла. Отыскав первый символ-разделитель, она помечает все предыдущие символы как [Поле 1]. Символы между первым и вторым разделителями обозначаются как [Поле 2] и т. д, 

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

Образец анализа входного файла:

Инструкция, или код операции awk состоит из шаблона (pattern) и связанной с ним процедуры (action), причем количество инструкций в сценарии awk может быть очень велико. 

шаблон {процедура}, или  шаблон — когда выводятся строки с данным шаблоном, или  {процедура} — когда действие выполняется для всех строк.           The Structure of an AWK Program ст.14

PS: Возможно не будет не правдой сказать, что понятие "pattern - шаблон" восходит ко временам формирования языков и на том этапе основным средством обработки текстов или потоков были регулярные выражения(по сути им и остаются), которые представляют собой набор шаблонов, состоящих как из специальных, так и обычных символов, поэтому понятие "шаблон" и "рег. выражение" близки между собой.

Существует также два специальных шаблона: BEGIN и END

Синтаксис базовых "Регулярных Выражений"  шаблонов, расширен следующими дополнениями:

"()"  скобки для группирования РВ;

"|"   логическое "или";

"+"  плюс, стоящий за РВ, означает любую последовательность вхождений этого РВ, начиная с первого;

"?"  знак вопроса, стоящий за РВ, означает 0 или 1 вхождений этого РВ.

Если никакой шаблон не указан, процедура выполняется для каждой записи из входного файла. {Тело процедуры заключается в фигурные скобки}. Чаще всего процедура осуществляет вывод информации на экран, но она может также содержать операторы присваивания, управляющие конструкции и встроенные функции. Если процедура не задана, утилита awk выводит на экран все содержимое записи, соответствующей шаблону.

Поля и записи

На поля текущей записи можно ссылаться следующим образом: $1, $2… $n. Этот метод называется идентификацией полей. Подобная схема обозначений значительно облегчает работу с полями. Например, в качестве ссылки на первое и третье поля достаточно указать:

    $1, $3

Обратите внимание на то, что идентификаторы полей разделяются запятой. Чтобы сослаться на все поля записи, содержащей пять полей, можно указать:

    $1, $2, $3, $4, $5

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

Когда в процессе просмотра утилита awk встречает символ новой строки, считается, что найден конец записи, после чего выполняется переход к новой строке, анализ новой записи и инициализация полей. Чтобы вывести на экран содержимое записи, в теле процедуры задается команда print со списком нужных полей.

Тестовый файл

AWK как и SED прежде всего "потоковые" редакторы, но для практическо-наглядной части, создадим файл например "grade.txt", на котором и будет основано большинство примеров. Файл этот должен содержать несколько записей из локальной базы данных секции каратистов (таков выбор m.Teynsli).

$ ~ cat > grade.txt

M.Tansley 05/99 48311 Green 8 40 44

N.Lulu 06/99 48317 green 9 24 26

O.Bunny 02/99 48 Yellow 12 35 28

P.Troll 07/99 4842 Brown-3 12 26 26

Q.Tansley 05/99 4712 Brown-2 12 30 28

# разделитель <Space>

^C

$ ~

Назначение полей таково:

    1 — имя;

    2 — дата получения пояса;

    3 — порядковый номер ученика;

    4 — полученный пояс;

    5 — возраст;

    6 — текущий рейтинг;

    7 — максимальное количество рейтинговых очков, которое можно было получить за   участие в  прошедшем соревновании.

Поля разделяются пробелами, поэтому при вызове утилиты awk можно не указывать опцию -F.

Изменить разделитель полей:


$ awk '$1=$1' FS=" " OFS=":_" grade.txt

M.Tansley:_05/99:_48311:_Green:_8:_40:_44

N.Lulu:_06/99:_48317:_green:_9:_24:_26

O.Bunny:_02/99:_48:_Yellow:_12:_35:_28

P.Troll:_07/99:_4842:_Brown-3:_12:_26:_26

Q.Tansley:_05/99:_4712:_Brown-2:_12:_30:_28

#:_разделитель:_<Space>

Соеденить строки используя sed:


$ cat grade.txt

M.Tansley 05/99 48311 Green 8 40 44

N.Lulu 06/99 48317 green 9 24 26

O.Bunny 02/99 48 Yellow 12 35 28

P.Troll 07/99 4842 Brown-3 12 26 26

Q.Tansley 05/99 4712 Brown-2 12 30 28

# разделитель <Space>


$ sed -e :a -e '/$/N;s/\n/ /;ta' grade.txt

M.Tansley 05/99 48311 Green 8 40 44 N.Lulu 06/99 48317 green 9 24 26 O.Bunny 02/99 48 Yellow 12 35 28 P.Troll 07/99 4842 Brown-3 12 26 26 Q.Tansley 05/99 4712 Brown-2 12 30 28 # разделитель <Space>

В примере слева, мы редактируем "поток" (естественно), что бы отредактировать файл его надо переписать:

$ awk '$1=$1' FS=" " OFS=":_" grade.txt > tmpfile; mv tmpfile grade.txt

$ cat grade.txt

M.Tansley:_05/99:_48311:_Green:_8:_40:_44

N.Lulu:_06/99:_48317:_green:_9:_24:_26

O.Bunny:_02/99:_48:_Yellow:_12:_35:_28

P.Troll:_07/99:_4842:_Brown-3:_12:_26:_26

Q.Tansley:_05/99:_4712:_Brown-2:_12:_30:_28

#:_разделитель:_<Space>

Сохранение выходных данных

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

 $ awk '{print $0}' grade.txt > grade.out

Второй способ заключается в применении команды tee - тройник. Выходные данные передаются в файл и одновременно отображаются на экране. Например:

$ awk '{print $0}' grade.txt | tee grade.out

Отображение всех записей

В приведенной ниже команде утилита awk просматривает файл grade.txt и, поскольку шаблон не указан, отображает содержимое всех записей:

$ ~ awk '{print $0}' grade.txt

M.Tansley 05/99 48311 Green 8 40 44

N.Lulu 06/99 48317 green 9 24 26

O.Bunny 02/99 48 Yellow 12 35 28

P.Troll 07/99 4842 Brown-3 12 26 26

Q.Tansley 05/99 4712 Brown-2 12 30 28

$ ~

DU:

# du -sb * | sort -nr | head | awk '{print $2}' | xargs du -sh

1.6G VMware

1.2G GNS3

783M Desktop  

548M VMware-Workstation-Full-16.0.0

191M Videos

156M Видео

119M Telegram

140M myapp_postgre

83M HP 

57M hplip-3.21.12


# cd /var

# du -sb * | sort -nr | head | awk '{print $2}' | xargs du -sh

5.8G lib

1.3G log

226M cache

25M backups

13M www

7.8M spool

2.9M mail

2.0M NX

76K tmp

4.0K opt

Так тоже не плохо:

$ du -x ${SYMLINKS} -k "$@" | sort -n | tail -100 | awk 'BEGIN { logx = log(1024); size[0]= "KB"; size[1]= "MB"; size[2]= "GB"; size[3]= "TB" } { x = $1; $1 = ""; v = int(log(x)/logx); printf ("%8.3f %s\t%s\n",x/(1024^v), size[v], $0) }'

Перечислить все разделы:

$ awk '/d.[0-9]/{print $4}' /proc/partitions

sda1

sda2

sda3

sda4

sda5

sda6

sda7

sda8

$ cat /proc/partitions

major     minor #blocks  name


   8        0  732574584 sda

   8        1      40131 sda1

   8        2   12843008 sda2

   8        3  193784216 sda3

   8        4          1 sda4

   8        5  351087616 sda5

   8        6  132285440 sda6

   8        7   40369152 sda7

   8        8    2158592 sda8

  11        0    1048575 sr0

Просто размеры разделов;

$ lsblk | grep -v part | awk '{print $1 "\t" $4}' 

NAME SIZE

loop0 4K

loop1 55.7M

loop2 105.8M

loop3 140K

loop4 91.7M

loop5 243.7M

sda 698.6G

sr0 1024M

Общий размер каждого подкаталога KB, MB, GB, TB:

$ du --max-depth=1 | sort -nr | awk ' BEGIN { split("KB,MB,GB,TB", Units, ","); } { u = 1; while ($1 >= 1024) { $1 = $1 / 1024; u += 1 } $1 = sprintf("%.1f %s", $1, Units[u]); print $0; } ' 

4.6 GB .

3.2 GB ./downloads

669.6 MB ./.cache

485.5 MB ./.config

127.5 MB ./.local

61.6 MB ./.cr3

34.2 MB ./vmware-host-modules

.........................

Убить все процессы юзера


$ ps -fu $USER | awk {'print $2'} | xargs kill [-9] 

Отображение отдельных полей всех записей

Предположим, требуется отобразить на экране только имена спортсменов и названия поясов, которыми они обладают. Соответствующие данные хранятся в полях $1 и $4, поэтому введем такую команду:

$ ~ awk '{print $1, $4}' grade.txt

M.Tansley Green

N.Lulu green

O.Bunny Yellow

P.Troll Brown-3

Q.Tansley Brown-2


LAN IP:

$ ifconfig | grep broadcast | awk '{print $2}'

172.16.193.1

172.16.11.1

192.168.1.201


$ ip a s wlan0 | awk -F'[/ ]+' '/inet[^6]/{print $3}'

192.168.1.201

Или так:

$ ifconfig | awk '/inet / {sub(/addr:/, "", $2); print $2}' 

127.0.0.1

192.168.228.1

172.16.22.1

192.168.1.8

Или так (только IP):

$ hostname -I | awk '{print $1}'

192.168.1.12


Узнать внешний IP-адрес маршрутизатора, можно с помощью "майора Хайдена" командой:

$ wget -O - -q icanhazip.com

$ curl -s icanhazip.com

*** The original icanhazip.com lives on, but the other services are going offline.😢(28.07.22)


Другой вариант узнать внешний адрес;

$ curl -s 'http://checkip.dyndns.org' | sed 's/.*Current IP Address: \([0-9\.]*\).*/\1/g' 


178.66.176.70




Напечатать nickname wireless:

$ nmcli -g name,type connection show --active | awk -F: '/ethernet|wireless/ { print $1 }'

myname


DF:

# df / | awk '{print $1}' | grep dev | xargs tune2fs -l | grep create

Filesystem created:       Thu Dec  7 16:52:00 2017

Найти роутер:

$ awk 'NR==2 {print $1}' /proc/net/arp

192.168.1.1

Так то же неплохо:

$ /sbin/route -n | grep "^0\.0\.0\.0" | awk '{ print $2 }' 

192.168.1.1

Распечатайте свои mac адреса:

$ ifconfig -a | sed '/eth\|wl/!d;s/ Link.*HWaddr//'

ether d4:be:d9:5a:b0:3b  txqueuelen 1000  (Ethernet)

ether 00:50:56:c0:00:01  txqueuelen 1000  (Ethernet)

ether 00:50:56:c0:00:08  txqueuelen 1000  (Ethernet)

wlp8s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  

mtu 1500

ether 68:5d:43:eb:05:0a  txqueuelen 1000  (Ethernet)

Функция:

lsmac() { ifconfig -a | sed '/eth\|wl/!d;s/ Link.*HWaddr//' ; }

Разделы использующие более 50%(или сколько надо) дискового пространства:

$ df -h |awk '{a=$5;gsub(/%/,"",a);if(a > 50){print $0}}' 

Filesystem      Size  Used Avail Use% Mounted on

/dev/sda10       77G   61G   12G  85% /Data

/dev/sda5       124G  106G   12G  90% /Share


Default gateway:

$ ip route | awk '/default/{print $3}'

192.168.1.1


Когда установлена ОСь.

$ ls -lct /etc/ | tail -1 | awk '{print $6, $7, $8}'

Dec 7 2017

$ ls -ldct /lost+found | awk '{print $6, $7, $8}'

Dec 7 2017


Название дистрибютива:

$ cat /etc/issue 

Debian GNU/Linux 12 \n \l


Лучше так:

$ lsb_release -a 

No LSB modules are available.

Distributor ID: Debian

Description: Debian GNU/Linux 12 (bookworm)

Release: 12

Codename: bookworm

Количество свободной памяти:

$ grep '^MemFree:' /proc/meminfo | awk '{ mem=($2)/(1024) ; printf "%0.0f MB\n", mem }'

1062 MB

$ free -m | awk '/Mem/ {print $4}'

1056

Найти самый новый файл в каталоге:

$ find ~/ -type f -printf "%T@|%p\n" 2>/dev/null | sort -n | tail -n 1| awk -F\| '{print $2}'

/home/user/.config/chromium/Profile 3/History-journal

Вывести используемый интерфейс:

$ ip addr | awk '/state UP/ {print $2}' | sed 's/.$//' 

wlp8s0

или:

$ route | grep -m1 ^default | awk '{print $NF}'

wlp8s0

Распечатать все интерфейсы:

$ awk '{print $1}' /proc/net/dev|grep :|sed "s/:.*//g"

lo

enp7s0

wlp8s0

vmnet1

vmnet8

Удалить все неиспользуемые ядра:

$ sudo aptitude remove $(dpkg -l | egrep '^ii linux-(im|he)' | awk '{print $2}' | grep -v `uname -r`);echo -e "Current version:  \c"; uname -r

No packages will be installed, upgraded, or removed.

0 packages upgraded, 0 newly installed, 0 to remove and 1195 not upgraded.

Need to get 0 B of archives. After unpacking 0 B will be used.

                                         

Current version:  6.0.0-kali3-amd64

Посмотреть наличные ядра:

$ ls /usr/src

$ ncdu /usr/src/

$ dpkg --list | grep linux-image

Посмотреть количество доступных обновлений для системы


$ apt-get -s upgrade | awk '/[0-9]+ upgraded,/ {print $1 " package updates are available"}' 

10 package updates are available

Вывести все пакеты от которых не зависит ни один пакет


$ dpkg-query --show --showformat='${Package}\t${Status}\n' | tac | awk '/installed$/ {print $1}' | xargs apt-cache rdepends --installed | tac | awk '{ if (/^ /) ++deps; else if (!/:$/) { if (!deps) print; deps = 0 } }' 

atmel-firmware

base-passwd

bash

bluez-firmware

bsdutils

.........

Вставить строку через определенное количество строк и пронумеровать выделенные области.


$ ls -l | awk '{if (NR % 7 == 0) print "##############################"; print}' | nl -s') ' -b p'#' 

        total 112

        -rw-r--r-- 1 user user  241 Dec 11 15:52 awk

        drwxr-xr-x 2 user user 4096 Sep 26 20:46 backup

        drwxr-xr-x 2 user user 4096 Sep 26 20:46 bin

        -rw-r--r-- 1 user user    0 Dec 10 14:25 cat

        -rw-r--r-- 1 user user 6382 Dec  2 20:01 conkyrc

     1) ##############################

        -rw-r--r-- 1 user user 2404 Oct  8 15:33 connkyrc

        -rw-r--r-- 1 user user    0 Dec  8 18:18 curl

        drwxr-xr-x 2 user user 4096 Oct  3 12:34 documents

        drwxr-xr-x 4 user user 4096 Dec 10 18:58 downloads

        -rw-r--r-- 1 user user  241 Dec 10 13:29 echo

        -rw-r--r-- 1 user user    0 Dec  8 18:29 exec

        -rw-r--r-- 1 user user 2287 Dec  9 03:01 foonction

     2) ##############################

        -rw-r--r-- 1 user user  241 Dec 10 14:31 ggrade.txt

        -rw-r--r-- 1 user user  209 Dec 11 20:11 grade.txt

        drwxr-xr-x 3 user user 4096 Dec 18 16:12 images

        -rw-r--r-- 1 user user 1424 Oct  8 15:09 logg

        -rw-r--r-- 1 user user    0 Dec  6 15:04 ls

        -rw-r--r-- 1 user user  132 Nov 29 17:03 mpass

        drwxr-xr-x 2 user user 4096 Sep 26 20:46 music

     3) ##############################


....следующие семь

PS: Нумерация строк команда — nl nl — нумерация строк


Просто пронумеровать


$ ls -l | sed "/^/=" | sed "N;s/\n/. /"

1. total 21476

2. -rw-r--r-- 1 user user  21846836 Dec 28  2019 4kvideodownloader_4.4.11-1_amd64.deb

3. -rw-r--r-- 1 user user        0 Apr 21 13:30 ask

4. -rw-r--r-- 1 user user      241 Dec 11 15:52 awk

5. drwxr-xr-x 2 user user     4096 Sep 26  2023 backup

6. drwxr-xr-x 2 user user     4096 Sep 26  2023 bin

............................................................................



Печать горизонтальной линии


$ printf "%`tput cols`s"|sed "s/ /_/g" 

______________________________________________________________________________

$ printf -v _hr "%*s" $(tput cols) && echo ${_hr// /${1--}} 

------------------------------------------------------------------------------


Вывести заданную строку из файла


$ awk 'NR==linenumber' filename


Печатать только четные строки файла


$ awk '{if (NR % 2 == 0) print $0}' filename


Распечатать строки из диапазона строк


$ cat -n grade.txt

     1 M.Tansley 05/99 48311 Green 8 40 44

     2 N.Lulu 06/99 48317 green 9 24 26

     3 O.Bunny 02/99 48 Yellow 12 35 28

     4 P.Troll 07/99 4842 Brown-3 12 26 26

     5 Q.Tansley 05/99 4712 Brown-2 12 30 28

     6 # разделитель <Space>

$ awk 'NR >= 3 && NR <= 6' grade.txt

O.Bunny 02/99 48 Yellow 12 35 28

P.Troll 07/99 4842 Brown-3 12 26 26

Q.Tansley 05/99 4712 Brown-2 12 30 28

# разделитель <Space>


Перечислить самые "жирные" пакеты


$ awk '{if ($1 ~ /Package/) p = $2; if ($1 ~ /Installed/) printf("%9d %s\n", $2, p)}' /var/lib/dpkg/status | sort -n | tail | awk 'BEGIN {print "\nInstalled-Size  Package name \n-----------------------------"} {print $1"\t        " $2} END {print "\nPS: Installed-Size - Общий объем дискового пространства, \nнеобходимого для установки пакета.\nhttps://www.debian.org/doc/debian-policy/ch-controlfields.html#installed-size"}'


Installed-Size  Package name 

-----------------------------

117419         libreoffice-core

143823         firmware-netronome

187651         openjdk-17-jre-headless

214208         virtualbox-7.0

227099         chromium

230978         firefox-esr

326369         google-chrome-stable

334238         fonts-noto-extra

398459         linux-image-6.1.0-13-amd64

398647         linux-image-6.1.0-12-amd64


PS: Installed-Size - Общий объем дискового пространства, 

необходимого для установки пакета.

https://www.debian.org/doc/debian-policy/ch-controlfields.html#installed-size

Для полноты картины сделать так:

$ apt-cache show libreoffice-core | grep Size

Installed-Size: 117419

Size: 32580380

И понимать разницу, между "размером дискового пространства" и "размером пакета"... и вообще надо сделать не две колонки а три.

Найти новый файл в текущей дирректории


$ > /tmp/newfile

$ cd /tmp

$ find . -type f -printf "%T@|%p\n" 2>/dev/null | sort -n | tail -n 1 | ls -l $(awk -F \| '{print $2}')  

-rw-r--r-- 1 user user 0 Dec  6 15:25 ./newfile


Функция:

$ nf () { find . -type f -printf "%T@|%p\n" 2>/dev/null | sort -n | tail -n 1 | ls -l $(awk -F \| '{print $2}'); }

$ nf

-rw-r--r-- 1 user user 0 Dec  6 15:25 ./newfile 


PS:awk -F \| ,здесь \| это разделитель полей, что бы вертикальная черта не интерпритировалась как логическое "или" ее надо экранировать, смотри man awk FS(field separator) и вывод команды find. Конечно возможно псевдоним был бы удобнее, но в силу ограничений накладываемых на механизм псевдонимов, возможно только функция, поскольку в отличие от функций, псевдонимы не позволяют осуществлять подстановку значений переменных, в нашем случае это $(awk -F \| '{print $2}').

Список файлов созданных/модифицированных в текущем каталоге сегодня:

$ ls -l --time-style=+%Y-%m-%d | awk "/$(date +'%Y-%m-%d')/ {print \$7}"

$ > /tmp/newfile

$ cd /tmp

$ ls -l --time-style=+%Y-%m-%d | awk "/$(date +'%Y-%m-%d')/ {print \$7}"

newfile

snap-private-tmp

ssh-XXXXXXyFTzFP

systemd-private-093c4643099f44d9abb6e5b0f92f5abc-colord.service-V1ZMK8

systemd-private-093c4643099f44d9abb6e5b0f92f5abc-ModemManager.service-cr9M0i

systemd-private-093c4643099f44d9abb6e5b0f92f5abc-ntpsec.service-xigihj

systemd-private-093c4643099f44d9abb6e5b0f92f5abc-systemd-logind.service-ISSK6n

systemd-private-093c4643099f44d9abb6e5b0f92f5abc-upower.service-M5NB7T

tracker-extract-3-files.1000

vmware-user

vmware-root


Распечатать размер файлов заданного расширения (у нас *.txt) в MB, в текущей дирректории:

$ find . -type f -iname '*.txt' -exec ls -lG {} \; | awk '{total = total + $4}END{print "scale=2;" total "/2^20"}' | bc

10.68


Посмотреть тип файловой системы


$ DIR=. ; FSTYPE=$(df -TP ${DIR} | grep -v Type | awk '{ print $2 }') ; echo "${FSTYPE}" 

ext4

Погода в терминале

curl http://wttr.in, если локализация не правильная, указать непосредственно: curl http://wttr.in/moscow

НО, нам интересен только заголовок поэтому:

$ curl http://wttr.in | sed '1,7! d' > wheather; clear; date >> wheather; cat wheather

Weather report: St Petersburg, Russia


     \  /       Partly cloudy

   _ /"".-.     -13(-20) °C    

     \_(   ).   ← 11 km/h      

     /(___(__)  10 km          

                0.0 mm

Fri Dec  8 07:51:46 PM MSK 2023

Функция:

$ forecast () { curl http://wttr.in | sed '1,7! d' > wheather; clear; date >> wheather; cat wheather; } 

Приветствие в открывающемся терминале


$ echo -e "12 morning\n15 afternoon\n24 evening" | awk '{ if ('`date +%H`'<$1) { print "Good "$2 " comrade";exit } }'

Good evening comrade

или так:

$ echo -e '12 morning! Today: '`date +%A`'\n15 afternoon Time:' "\033[1m`date +%T`\033[0m"'\n24  evening! Now:' "\033[1m`date +%T`\033[0m"'' | awk '{ if ('`date +%H`'<$1) { print "Good "$2, $3, $4"";exit } }'

Good evening! Now: 15:25:31

PS: добавить в профильный файл, например .bashrc (не всякая "реализация" интерпритатора будет читать .profile, а .bashrc, прочтет точно) конечно при желании можно раскрасить, выбрать шрифт и прочее ...(/home/Doc/reference-book-of-shell )

Найти устройство по точке монтирования


$ df -P | awk '$6=="/Data" {print $1}'

/dev/sda10

Удалить все процессы найденные посредствам grep


$ for line in `ps aux | grep [string] | awk '{print $2}'`; do sudo kill $line; done;

Убить процесс найденный посредствам "ps"


$ ps ux|grep <имя процесса>|awk '{print $2}'|xargs -n 1 kill

Распечатать время последнего изменения в формате «дата — файл»


$ ls -alt /home/$USER | awk '{ print $6 " " $7 " -- " $9 }' | column -c 140

  -- Dec 10 -- tmpgrade.txt Oct 3 -- .mozilla

Dec 26 -- . Dec 10 -- echo Sep 28 -- .selected_editor

Dec 26 -- .bash_history Dec 9 -- .vmware Sep 26 -- .gnome

Dec 26 -- .xsession-errors Dec 9 -- .ssh Sep 26 -- .pki

Dec 26 -- .lesshst Dec 8 -- exec Sep 26 -- sudo

Dec 26 -- .Xauthority Dec 8 -- curl Sep 26 -- .sudo_as_admin_successful

Dec 25 -- speedtest Dec 8 -- wttr.in Sep 26 -- .gtk-bookmarks

Dec 25 -- wheather Dec 8 -- .cache Sep 26 -- music

Dec 21 -- .config Dec 7 -- sed Sep 26 -- tmp

Dec 20 -- .viminfo Dec 6 -- ls Sep 26 -- backup

Dec 20 -- images Dec 2 -- conkyrc Sep 26 -- bin

Dec 19 -- foonction Dec 2 -- .flags Sep 26 -- .fonts.conf

.....................................................................

Утилита: column


Распечатать десятку самых жирных файлов используя du, в нашем случае из $HOME


$ for i in `du --max-depth=1 $HOME | sort -n -r | awk '{print $1 ":" $2}'`; do size=`echo $i | awk -F: '{print $1}'`; dir=`echo $i | awk -F: '{print $NF}'`; size2=$(($size/1024)); echo "$size2 MB used by $dir"; done | head -n 10 

11951 MB used by /home/user

5432 MB used by /home/user/.local

2377 MB used by /home/user/videos

1365 MB used by /home/user/.config

1290 MB used by /home/user/.cache

925 MB used by /home/user/documents

407 MB used by /home/user/downloads

61 MB used by /home/user/.cr3

34 MB used by /home/user/vmware-host-modules

26 MB used by /home/user/.mozilla


Посмотреть загруженные модули ядра


$ sudo lsmod | cut -d' ' -f1 | xargs modinfo | egrep '^file|^desc|^dep' | sed -e'/^dep/s/$/\n/g' 

modinfo: ERROR: Module Module not found.

filename:       /lib/modules/6.1.0-12-amd64/kernel/drivers/misc/vmnet.ko

description:    VMware Virtual Networking Driver.

depends:        


filename:       /lib/modules/6.1.0-12-amd64/kernel/net/vmw_vsock/vmw_vsock_vmci_transport.ko

description:    VMCI transport for Virtual Sockets

depends:        vsock,vmw_vmci


filename:       /lib/modules/6.1.0-12-amd64/kernel/net/vmw_vsock/vsock.ko

description:    VMware Virtual Socket Family

depends:        


.........................................................


Отображение заголовка отчета

Результат работы предыдущей команды выглядит не слишком привлекательно. Рассмотрим, какие шаги можно предпринять, чтобы улучшить его. Прежде всего выровняем границы полей посредством символов табуляции. Табуляция создается с помощью Escape–последовательности \t (об управляющих последовательностях речь пойдет ниже). Кроме того, для придания отчету солидности добавим к нему заголовок, включающий названия полей, а также разделительную линию, которая отображается в отдельной строке благодаря Escape–последовательности \n.: Заголовок отчета формируется в процедурной части шаблона begin.

$ ~ awk 'BEGIN {print "Name Belt\n --------------"} \

{print $1 " \t" $4}' grade.txt


Name Belt

---------------------------

Tansley Green 

Lulu green 

Bunny Yellow 

Troll Brown-3 

Tansley Brown-2 

$ ~

Более практический пример, вывести 10 наиболее загруженных процессов:

$ ps axo rss,comm,pid | awk '{ proc_list[$2]++; proc_list[$2 "," 1] += $1; } END { for (proc in proc_list) { printf("%d\t%s\n", proc_list[proc "," 1],proc); }}' | sort -n | tail -n 10 | sort -rn 

686MB telegram-desktop

246MB gnome-shell

128MB systemd-journal

127MB mariadbd

118MB Xorg

103MB dockerd

84MB apache2

76MB evolution-alarm

58MB containerd

Усугубим "изврашение" при помощи BEGIN и END:

$ ps axo rss,comm,pid | awk '{ proc_list[$2]++; proc_list[$2 "," 1] += $1; } END { for (proc in proc_list) { printf("%d\t%s\n",  proc_list[proc "," 1],proc); }}' | sort -n | tail -n 10 | sort -rn | awk '{$1/=1024;printf "%.0fMB\t",$1}{print $2}' | awk 'BEGIN {print "\n======= TOP TEN ======="} {print $1" \t" $2} END {print "========= END =========="}'


======= TOP TEN =======

4101MB chromium

686MB telegram-desktop

246MB gnome-shell

128MB systemd-journal

127MB mariadbd

118MB Xorg

103MB dockerd

84MB apache2

76MB evolution-alarm

58MB containerd

========= END ==========

Десять основных процессов  с процентами от общего объема ОЗУ: 

$ TR=`free|grep Mem:|awk '{print $2}'`;ps axo rss,comm,pid|awk -v tr=$TR '{proc_list[$2]+=$1;} END {for (proc in proc_list) {proc_pct=(proc_list[proc]/tr)*100; printf("%d\t%-16s\t%0.2f%\n",proc_list[proc],proc,proc_pct);}}'|sort -n |tail -n 10

24224 tracker-miner-f 0.62%

28324 systemd-journal 0.73%

33920 qbittorrent     0.87%

37252 gjs             0.96%

38280 fwupd           0.98%

43328 packagekitd     1.11%

53548 Xorg            1.37%

63004 gnome-software  1.62%

213412 gnome-shell     5.48%

2683192 chromium        68.89%

Процессы по количеству открытых файловых дескрипторов

$ lsof | awk '{print $1}' | sort | uniq -c | sort -rn | head

  49786 chromium

   7222 gnome-shell

   4138 evolution

   4032 gjs

   3653 qbittorrent

   2322 gnome-soft

   1595 conky

   1400 Xorg

   1146 xdg-desktop

   1102 gnome-session


$ history | awk '{a[$2]++}END{for(i in a){print a[i] " " i}}' | sort -rn | head | awk 'BEGIN {print "\n"}{print $1" \t-" $2}'


183 -sudo

100 -ls

84 -systemctl

60 -for

50 -history

47 -ps

40 -netstat

34 -vim

31 -cd

28 -echo

PS: оптимальным будет настроить под себя ReadLine:

https://wiki.archlinux.org/title/Readline     https://www.opennet.ru/docs/RUS  

При работе со строками используем SED

Удалить строку, интервал между строками используя sed:

Удалить третью строку: sed '3d' file

Удалите строку, содержащую ряд букв: sed '/awk/d' file

Удалить последнюю строку: sed '$d' file

Удалить интервал между строками 7 и 9: sed '7,9d' file

PID выбранного окна GUI:

$ xprop | awk '/PID/ {print $3}'

2950

Cписок процессов по прослушиваемому порту:

$ sudo netstat -ntlp | grep -w 80 | awk '{print $7}' | cut -d/ -f1

972

$ sudo netstat -ntlp | grep -w 54560 | awk '{print $7}' | cut -d/ -f1

17226

$ lsof -p 17226 | awk '{print $1}'

COMMAND

qbittorrent

qbittorrent

.........

Функция pid процесса, по его имени:

$ pidof () { ps acx | egrep -i $@ | awk '{print $1}'; }

$ pidof chromium

4459

4559

4560

4571

4619

......

$ pidof Xorg

1811

Текстовой график количества подключений

$ netstat -an | grep ESTABLISHED | awk '{print $5}' | awk -F: '{print $1}' | sort | uniq -c | awk '{ printf("%s\t%s\t",$2,$1) ; for (i = 0; i < $1; i++) {printf("*")}; print "" }'


108.177.14.139 1 *

108.177.14.188 1 *

151.101.194.137 1 *

173.194.220.94 1 *

192.168.1.1 1 *

209.85.233.94 2 **

2.19.198.50 1 *

5.255.255.77 1 *

64.233.164.95 1 *

87.250.251.89 2 **

Все IP соединения хоста:

$ sudo netstat -lantp | grep ESTABLISHED |awk '{print $5}' | awk -F: '{print $1}' | sort -u


172.67.217.229

193.106.95.138

5.255.255.77

52.85.49.39

64.233.163.94

74.125.205.188

77.88.21.119

87.240.132.67

87.250.250.121

87.250.251.89

Отображение резюме отчета

Чтобы добавить в конец отчета строку "end‑of‑report", следует воспользоваться шаблоном END. Этот шаблон употребляется для обозначения действий, которые выполняются после обработки последней записи входного файла.

$ ~ awk 'BEGIN {print "Name\n------------ "} {print $1} \

END {print "end‑of‑report"}' grade.txt


Name

------------

M.Tansley

N.Lulu

O.Bunny

P.Troll

Q.Tansley

end-of-report

$ ~

Следует обратить внимание на обратный слеш используемый awk как символ перевода строки (возврат каретки), в отличии от bash,sh написание будет просто слеш, а не так например:

$ ~ echo -e "строка 1\nстрока 2"

строка 1

строка 2

$ ~

И если точнее, то выше приведенный сценарий awk состоит как бы из "двух частей"

между которыми будет напечатано приглашение в виде (1:) или (>) в зависимости как вы его указали  в профильных файлах, в качестве переменной PS2=... ,которое не выводится, и если, по частям и если PS2=> (echo $PS2) то примерно так:

$ ~ awk 'BEGIN {print "Name\n------------ "} {print $1} \

> END {print "end‑of‑report"}' grade.txt


Name

------------

M.Tansley

N.Lulu

O.Bunny

P.Troll

Q.Tansley

end‑of‑report

$ ~

PS: Использование шаблонов BEGIN и END, это далеко не только "красота отчетов" (естественно). Во многих ситуациях может потребоваться выполнить код инициализации до того, как awk начнет обработку текста из входного файла (потока), как раз для таких ситуаций awk позволяет использовать шаблон BEGIN, блок BEGIN оценивается до того, как awk начнет обработку входного файла, отличное место для инициализации переменной FS (разделитель полей), вывода заголовка или инициализации других глобальных переменных, на которые вы будете ссылаться позже. 

Как и шаблон END, Awk выполняет этот шаблон после обработки всех строк входного файла. Как правило, блок END используется для выполнения окончательных вычислений или печати сводок, которые должны появиться в конце выходного потока, примером может послужить скрипт который слева и использование первого END в третьей строке, если выполнять его по строчно добавляя > {print $1,$2}' , то можно без труда разобраться во всех его "замысловатостях".

$ netstat -ntu | awk '{print $5}'|cut -d: -f1 -s|sort|uniq -c|sort -nk1 -r | awk 'BEGIN {print "\n=== NETSTAT-TCP/UDP Connection ==="} {print $1" \t" $2} END {print "========== netstat -ntu ==========="}'


=== NETSTAT-TCP/UDP Connection ===

6 62.217.160.2

2 62.217.160.4

2 62.217.160.3

1 8.8.8.8

1 77.88.55.88

1 74.125.131.95

1 62.217.160.12

1 173.194.73.199

========== netstat -ntu ===========

Количество подключений на удаленные адреса;

$ netstat -antu | awk '{print $5}' | awk -F: '{print $1}' | sort | uniq -c | sort -n

      1 151.101.130.137

      1 192.168.1.1

      1 74.125.205.188

      1 Address

      1 and

     11 

     18 0.0.0.0

Список установленных соединений по "назначению" и идентификатору приложения.

$ netstat | grep EST | awk '{print $5}' | sort

192.168.1.1:bootps # bootstrap protocol

e2a.google.com:https

lh-in-f102.1e100.:https

lh-in-f95.1e100.n:https

li-in-f199.1e100.:https

li-in-f199.1e100.:https

lm-in-f132.1e100.:https

lo-in-f84.1e100.n:https

lr-in-f94.1e100.n:https

lu-in-f188.1e100.n:5228 #порт 5228

List the number and type of active network connections

# netstat -ant | awk '{print $NF}' | grep -v '[a-z]' | sort | uniq -c

      2 CLOSE_WAIT

     20 ESTABLISHED

      7 LISTEN

# netstat -antp | grep ::80*

tcp6       0      0 :::80      :::*    LISTEN      1023/apache2  

# NETSTAT   Статистика сетевых соединений    ss   Man ss


$ lsof -Pni4 # | grep LISTEN (check open ports)

-P no port names

-n no host names

-i select IPv[4or6]

Вывести имена всех сетевых интерфейсов и IPv4-адресов:

$ PS: ifconfig часто бывает излишне "богатая" утилита

$ alias ips='ip a | awk '\''/inet /&&!/ lo/{print $NF,$2}'\'' | column -t' 

$ ips

wlan0   192.168.1.201/24

vmnet1  172.16.193.1/24

vmnet8  172.16.11.1/24

$ ip -f inet a | awk '/inet / { print $2 }'

127.0.0.1/8

192.168.1.201/24

172.16.193.1/24

172.16.11.1/24

$ MAC адреса интерфейсов:

$ for f in /sys/class/net/*; do echo -e "$(basename $f)\t$(cat $f/address)"; done

eth0 d4:be:d9:5a:b0:3b

lo 00:00:00:00:00:00

vmnet1 00:50:56:c0:00:01

vmnet8 00:50:56:c0:00:08

wlan0 68:5d:43:eb:05:0a

$ cat /sys/class/net/*/address

d4:be:d9:5a:b0:3b

00:00:00:00:00:00

00:50:56:c0:00:01

00:50:56:c0:00:08

68:5d:43:eb:05:0a

Локализация установленных соединений:

$ sudo apt install geoip-bin geoip-database

$ geoiplookup 8.8.8.8

GeoIP Country Edition: US, United States

$ for i in $(netstat --inet -n|grep ESTA|awk '{print $5}'|cut -d: -f1);do geoiplookup $i;done 

GeoIP Country Edition: RU, Russian Federation

GeoIP Country Edition: RU, Russian Federation

GeoIP Country Edition: NL, Netherlands

GeoIP Country Edition: US, United States

GeoIP Country Edition: US, United States

GeoIP Country Edition: US, United States

Вывести имя текущего соединения:

$ nmcli -g name,type connection show --active|awk -F: '/ethernet|wireless/ { print $1 }'

ROSTELECOM

PS: Для беспроводных соединения существует удобная утилита iw, если добавить AWK, будут получаться интересные отчеты

Все порты прослушивания, плюс PID и FD


$ lsof -Pan -i tcp -i udp 

COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME

chrome  3044  164u  IPv4 188458      0t0  UDP 224.0.0.251:5353 

chrome  3044  169u  IPv4 188460      0t0  UDP 224.0.0.251:5353 

chrome  3044  253u  IPv4 188462      0t0  UDP 224.0.0.251:5353

................................ 

Обработка сообщений об ошибках

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

$ ~ awk 'BEGIN {print "Name\n---------------- "} {print $1} \

> END {print "\end-of-report}' grade.txt


awk: cmd. line:2: END {print "\end-of-report}

awk: cmd. line:2: ^ unterminated string

awk: cmd. line:2: END {print "\end-of-report}

awk: cmd. line:2: ^ syntax error

$ ~

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

Более понятным является сообщение об ошибке, возникающей при создании ссылки на несуществующий файл:

$ ~ awk 'END {print "End‑of‑report"}' grades.txt

awk: fatal: cannot open file `grades.txt' for reading (Нет такого файла или каталога)

$ ~

Ввод данных с клавиатуры 

 Давайте посмотрим, что произойдет, если не указать файл grade.txt в командной строке:

 $ ~ awk 'BEGIN {print "Name Belt\n----------------------- "} \

> {print $1" \t"$4}'

Name Belt

-----------------------

>

^C

$ ~

С помощью шаблона BEGIN на экран выводится заголовок отчета, при этом сам отчет пуст, а утилита awk ожидает получения входных данных с клавиатуры (об этом свидетельствует строка приглашения >). Вы должны ввести их вручную. После нажатия клавиши [Enter] введенная строка интерпретируется как входная запись и по отношению к ней выполняются соответствующие инструкции. По завершении ввода данных нажмите [Ctrl+D]. Подобный метод работы применяется довольно редко, поскольку чреват большим количеством опечаток и ошибок.

$ awk 'BEGIN {print "Name Belt\n----- "} {print $1" \t"$4}'

Name Belt

-----

^C

Метасимволы

Если коротко о регулярных выражениях, неизбежном атрибуте любого языка, то: в сценарии awk регулярное выражение выделяется с обеих сторон символами косой черты: /регулярное_выражение/. Например, если в текстовом файле нужно найти строку, содержащую слово "Green", следует задать шаблон /Green/. Перечисленные метасимволы могут встречаться в регулярных выражениях утилиты awk:  \ ^ $ . [ ] | ( ) * + ?

Следует остановиться на описании двух метасимволов, которые специфичны для awk и не применяются в команде grep и редакторе sed.

+     Указывает на то, что предыдущий символ встречается один или несколько раз. Например: 

выражение /t+/ соответствует одной или нескольким буквам 't', а 

выражение /[а–z]+/ — любой последовательности строчных букв.

?     Указывает на то, что предыдущий символ встречается не более одного раза. Например:                            

выражение /xy?z/ соответствует строкам "XYZ" и "XZ".

Стоит так-же обратить внимание на использование прямого и обратного слеша, в зависимости от цели.

Операторы

В awk существует достаточно много операторов, манипулирующих числами, строками, переменными, полями и элементами массива. 

Список основных операторов:

Операторы сравнения

Простейшие инструкции awk создаются с помощью операторов:

Проверка на совпадение

Оператор ~ (тильда) позволяет находить поля, соответствующие заданному шаблону (регулярному выражению). Обычно он применяется в конструкции if, условная часть которой заключается в круглые скобки.

Предположим, из файла grade.txt требуется извлечь информацию о владельцах коричневых поясов. Для этого нужно найти строки, содержащие слово "Brown" (коричневый):

$ ~ awk '{if($4 ~ /Brown/) print $0}' grade.txt

P.Troll 07/99 4842 Brown-3 12 26 26

Q.Tansley 05/99 4712 Brown-2 12 30 28

$ ~

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

$ ~ awk '$0 ~ /Brown/' grade.txt

P.Troll 07/99 4842 Brown-3 12 26 26

Q.Tansley 05/99 4712 Brown-2 12 30 28

$ ~

Приведенная команда означает следующее: если в строке встречается слово "Brown", вывести ее на экран.

Проверка на равенство

Допустим, необходимо получить информацию об ученике с номером 48. Показанная ниже команда не позволит решить данную задачу, поскольку в файле есть множество номеров, содержащих последовательность цифр "48":

$ ~ awk '{if($3 ~ /48/) print $0}' grade.txt

M.Tansley 05/99 48311 Green 8 40 44

N.Lulu 06/99 48317 green 9 24 26

O.Bunny 02/99 48 Yellow 12 35 28

P.Troll 07/99 4842 Brown-3 12 26 26

$ ~

Чтобы найти точное совпадение, воспользуйтесь оператором ==:

$ ~ awk '$3 == "48"' grade.txt

O.Bunny 02/99 48 Yellow 12 35 28

$ ~

Проверки на несовпадение и неравенство 

Иногда требуется извлечь те строки, которые не соответствуют шаблону. Для этих целей предназначен оператор !~, выполняющий проверку на неравенство регулярному выражению. Давайте, например, выведем список всех учеников, не являющихся обладателями коричневого пояса:

$ ~ awk '$0 !~ /Brown/' grade.txt

M.Tansley 05/99 48311 Green 8 40 44

N.Lulu 06/99 48317 green 9 24 26

O.Bunny 02/99 48 Yellow 12 35 28

$ ~

He забывайте, что по умолчанию утилита awk выводит на экран все записи, отвечающие указанному критерию отбора, поэтому нет необходимости задавать какое‑либо действие. Если вместо предыдущей команды указать

$ ~ awk '$4 != "Brown"' grade.txt

M.Tansley 05/99 48311 Green 8 40 44

N.Lulu 06/99 48317 green 9 24 26

O.Bunny 02/99 48 Yellow 12 35 28

P.Troll 07/99 4842 Brown-3 12 26 26

Q.Tansley 05/99 4712 Brown-2 12 30 28

$ ~

получим ошибочный результат. Эта команда означает, что требуется найти строки, в которых четвертое поле не равно "Brown". Такому критерию удовлетворяют все строки в файле. Конечно, если нужно найти обладателей поясов, отличных от "Brown-2", можно применить следующую команду:

$ ~ awk '$4 != "Brown-2"' grade.txt

M.Tansley 05/99 48311 Green 8 40 44

N.Lulu 06/99 48317 green 9 24 26

O.Bunny 02/99 48 Yellow 12 35 28

P.Troll 07/99 4842 Brown-3 12 26 26

$ ~

Обратите внимание на один важный момент: строка "Brown-2" заключена в двойные кавычки. Если этого не сделать, четвертое поле будет сравниваться с содержимым переменной Brown-2. Вряд ли в вашем интерпретаторе существует такая переменная, поэтому вместо нее будет подставлена пустая строга, и вы получите совершенно другой результат.

Проверка "меньше чем"

Допустим, нужно определить, кто из учеников не смог набрать максимального количества очков на соревновании. Для выполнения проверки достаточно сравнить набранный рейтинг (поле 6) с общей суммой возможных очков (поле 7). Также поместим в отчет небольшое сообщение.

$ ~ awk '{if($6 < $7) print $1 " — try better at the next competition"}' grade.txt

M.Tansley — try better at the next competition

N.Lulu — try better at the next competition

$ ~

Проверка "меньше или равно" 

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

$ ~ awk '{if($6 <= $7) print $1}' grade.txt

M.Tansley

N.Lulu

P.Troll

$ ~

Проверка "больше чем"

Следующая команда формирует список лидеров соревнования:

$ ~ awk '{if ($6 > $7) print $1}' grade.txt

O.Bunny

Q.Tansley

$ ~

Логические операторы

Логические операторы или булевы (boolean), обладающие двумя значениями true и false, позволяют формировать сложные выражения, позволяющие выполнять проверку нескольких условий. Существует три логических оператора:

Оператор логического И  &&

Предположим, перед нами поставлена задача выяснить, кому был присвоен зеленый пояс в мае 1999 года. Строки, отвечающие этому условию, должны в первом поле содержать значение "05/99", а во втором — "Green":

$ ~ awk '{if($2 == "05/99" && $4 == "Green") print $0}' grade.txt

M.Tansley 05/99 48311 Green 8 40 44

$ ~

Оператор логического ИЛИ  || 

Чтобы получить список учеников, обладающих желтым или коричневым поясом, воспользуйтесь оператором | |:

 $ ~ awk '{if($4 == "Yellow" || $4 ~ /Brown/) print $0}' grade.txt

O.Bunny 02/99 48 Yellow 12 35 28

P.Troll 07/99 4842 Brown-3 12 26 26

Q.Tansley 05/99 4712 Brown-2 12 30 28

$ ~

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

$ ~ awk '$4 ~ /Yellow|Brown/' grade.txt

O.Bunny 02/99 48 Yellow 12 35 28

P.Troll 07/99 4842 Brown-3 12 26 26

Q.Tansley 05/99 4712 Brown-2 12 30 28

$ ~

Операторы присваивания и арифметические операторы

С помощью операторов присваивания и арифметических операторов можно создавать в сценариях awk локальные переменные и манипулировать их значениями.

 Создание локальных переменных

При разработке сценариев awk не всегда удобно работать с идентификаторами полей. Лучше создать переменную, содержащую значение поля, и присвоить ей выразительное имя, чтобы в дальнейшем ссылаться на поле по имени. Подобную переменную можно получить с помощью конструкции следующего вида:  имя_переменной = $n   где n -cуществующий номер поля.

В следующем примере мы создадим две переменные: name, содержащую имена учеников (поле 1), и belts, содержащую названия поясов (поле 4). Затем будет произведен поиск учеников, обладающих желтым поясом.

$ ~ awk '{name=$1; belts=$4; if(belts ~ /Yellow/) print name " is belt " belts}' grade.txt

O.Bunny is belt Yellow

$ ~

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

Проверка значения поля

В следующем примере мы проверим, кто из учеников набрал в соревнованиях менее 27 очков. В первом варианте команды значение поля $6 непосредственно сравнивается с числом 27:

$ ~ awk '$6 < 27' grade.txt

N.Lulu 06/99 48317 green 9 24 26

P.Troll 07/99 4842 Brown-3 12 26 26

$ ~

Более универсальный способ заключается в том, чтобы перед обработкой входного файла, в процедурной части шаблона BEGIN, создать, как в настоящей программе, набор локальных переменных с нужными значениями и ссылаться на них, когда потребуется. Конечно, этот прием неэффективен в случае одноразовых команд, зато очень полезен в больших сценариях, так как позволяет легко вносить в них изменения. Во втором примере мы создадим переменную baseline и присвоим ей значение 27, а затем сравним с ней интересующее нас поле $6:

$ ~ awk 'BEGIN {BASELINE=27} {if ($6 < BASELINE) print $0}' grade.txt

N.Lulu 06/99 48317 green 9 24 26

P.Troll 07/99 4842 Brown-3 12 26 26

$ ~

Изменение значения числового поля 

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

В следующем примере на экран выводятся имена учеников и их рейтинговые очки, а рейтинг ученика по имени M. Tansley уменьшается на единицу:

$ ~ awk '{if($1=="M.Tansley") $6=$6-1; print $1, $6}' grade.txt

M.Tansley 39

N.Lulu 24

O.Bunny 35

P.Troll 26

Q.Tansley 30

$ ~

Изменение значения текстового поля

Для изменения значения текстового поля достаточно применить к нему оператор присваивания. Следующая команда при выводе на экран добавляет к имени ученика J. Troll дополнительный инициал:

$ ~ awk '{if($1 == "P.Troll") $1="J.L.Troll"; print $1}' grade.txt

M.Tansley

N.Lulu

O.Bunny

J.L.Troll

Q.Tansley

$ ~

He забывайте о том, что строковые константы следует заключать в двойные кавычки. Поскольку имена учеников в данном случае содержат точки, утилита awk выдаст сообщение об ошибке при отсутствии кавычек, так как точка является метасимволом и встречается в непонятном контексте.

Исключить строку с помощью AWK

$ awk '{sub("String","")}1'

Например:

$ awk '{sub("N.Lulu 06/99 48317 green 9 24 26","")}1' grade.txt


M.Tansley 05/99 48311 Green 8 40 44


O.Bunny 02/99 48 Yellow 12 35 28

P.Troll 07/99 4842 Brown-3 12 26 26

Q.Tansley 05/99 4712 Brown-2 12 30 28

# разделитель <Space>

Отображение только измененных записей

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

$ ~ awk '{if($1 == "P.Troll") {$1="J.L.Troll"; print $1}}' grade.txt

J.L.Troll

$ ~

Исключить несколько столбцов с помощью AWK


$ awk '{$1=$3="";print}' grade.txt   #равно awk '{$1=$3=""}1'

 05/99  Green 8 40 44

 06/99  green 9 24 26

 02/99  Yellow 12 35 28

 07/99  Brown-3 12 26 26

 05/99  Brown-2 12 30 28

$ awk '{$2=$3=$5=$6=$7="";}1' grade.txt

M.Tansley   Green      

N.Lulu      green   

O.Bunny     Yellow   

P.Troll     Brown-3   

Q.Tansley   Brown-2  

Awk рассматривает "1" как истину и поэтому выполняет действие по умолчанию, действие по умолчанию печать. 

 Создание нового поля

Аналогично локальным переменным в сценарии awk можно создавать новые поля. Например, мы можем создать поле $8, содержащее разницу полей $6 и $7 в том случае, если значение в поле $7 больше, чем в поле $6:

$ ~ awk 'BEGIN {print "Name\t\tDifference"} {if($6 < $7) {$8=$7-$6; print $1" \t"$8}}' grade.txt

Name            Difference

M.Tansley       4

N.Lulu  2

$ ~

Суммирование столбцов 

Для вычисления суммарного рейтинга учеников секции мы создадим переменную tot и с помощью выражения tot+=$6 будем прибавлять к ней значение поля $6 при обработке каждой записи. По завершении обработки записей в процедурной части шаблона END итоговое значение переменной tot будет выведено на экран.

$ ~ awk 'tot+=$6; END {print "Club student total points: " tot}' grade.txt

M.Tansley 05/99 48311 Green 8 40 44

N.Lulu 06/99 48317 green 9 24 26

O.Bunny 02/99 48 Yellow 12 35 28

P.Troll 07/99 4842 Brown-3 12 26 26

Q.Tansley 05/99 4712 Brown-2 12 30 28

Club student total points: 155

$ ~

Вероятно, вы заметили, что утилите awk не было дано указание выводить на экран все записи oна сделала это сама. Причина такого поведения заключается в том, что выражение tot+=$6 относится к шаблонной части инструкции и не задает критерия отбора строк, т.е. применяется ко всем записям. А поскольку процедурная часть этого шаблона отсутствует, выполняется действие по умолчанию — команда print SO.

Если файл велик, можно не выводить на экран все записи, а лишь отобразить итог. Для этого достаточно взять выражение tot+=$6 в фигурные скобки, чтобы перенести его в процедурную часть инструкции:

$ ~ awk '{tot+=$6}; END {print "Club student total points: " tot}' grade.txt

Club student total points: 155

$ ~

Счетчик пользовательских процессов:

$ ps aux |awk '{$1} {++P[$1]} END {for(a in P) if (a !="USER") print a,P[a]}'

message+ 1

rtkit 1

colord 1

dell 97

polkitd 1

www-data 6

root 164


$ ps hax -o user --sort user | uniq -c

      1 colord

     98 dell

      1 messagebus

      1 polkitd

    164 root

      1 rtkit

      6 www-data

Найти все файлы размером более 10 МБ, отсортировать в порядке убывания размера:

# find . -size +10240k -exec ls -l {} \; | awk '{ print $5,"",$9 }'|sort -rn

548382816  ./VMware-Workstation-Full-16.0.0/VMware-Workstation-Full-16.2.3-19376536.x86_64.bundle

538839908  ./VMware/VMware-Workstation-Full-17.0.0-20800274.x86_64.bundle

536072059  ./VMware/VMware_15.5/VMware-Workstation-Full-15.5.2-15785246.x86_64.bundle

527417929  ./VMware/VMware-Workstation-Full-16.1.2-17966106.x86_64.bundle

Показать разделы, которые используются более чем на 70%

# df -h |awk '{a=$5;gsub(/%/,"",a);if(a > 70){print $0}}'

Filesystem      Size  Used Avail Use% Mounted on

/dev/sda7        38G   34G  2.2G  94% /

/dev/sda6       124G  109G  9.3G  93% /Data

Показать количество сетевых карт, портов на каждую сетевую карту и адрес PCI:

$ lspci | grep Ether | awk '{ VAR=$1; split(VAR,ARR,"."); count[ARR[1]]++; LINE=$0; split(LINE,LINEARR,":"); LINECOUNT[ARR[1]]=LINEARR[3]; } END { for(i in count) { printf("PCI address: %s\nPorts: %d\nCard Type: %s\n", i, count[i], LINECOUNT[i]) } }'


PCI address: 07:00

Ports: 1

Card Type:  Realtek Semiconductor Co., Ltd. RTL810xE PCI Express Fast Ethernet controller (rev 05)

Суммирование размеров файлов 

При просмотре содержимого каталога часто требуется узнать общий размер всех файлов в нем, исключая файлы в подкаталогах и скрытые файлы. Алгоритм решения этой задачи таков: результаты работы команды ls -l (формирует список файлов с расширенной информацией о них) направляются утилите awk, которая удаляет записи, начинающиеся с символа 'd' (признак каталога), и вычисляет сумму по 5–му столбцу (содержит размер файла).

Представленная ниже команда отображает список файлов текущего каталога (имя файла берется из 9–го столбца), указывая размер каждого из них, а в конце выводит суммарный размер файлов, накопленный в переменной tot:

$ ~ ls -l | awk '/^[^d]/ {print $9"\t"$5; tot+=$5} END {print "total KB: "tot}'

LogAnalyser.png 242620

big     702

butt.jpg*       26558

date    69987

dvb-fe-xc5000-1.6.114.fw        12401

dvb-usb-dib0700-1.20.fw 33768

find.txt        7055732

grade.txt       176

grep.txt        0

................................

total KB: 15956555

$ ~

Если необходимо включить в список скрытые файлы, следует вместо команды 

ls -l задать команду ls -la.

Количество символов в каждой строке:

$ awk ' BEGIN { FS=""} { print NF } ' myfile

7

7

7

4

3

7

4

3

7

$ cat myfile

line -1

line -2

line -3

vxbh

jjj

ubdjuys

vxbh

jjj

ubdjuys

Использование памяти отдельной программой:

$ ps auxf | grep chromium | grep -v grep | grep -v defunct | awk '{sum=sum+$6}; END {print sum/1024}'

2869.57

$ ps auxf | grep apache2 | grep -v grep | grep -v defunct | awk '{sum=sum+$6}; END {print sum/1024}'

14.2852

$ ps auxf | grep gnome-shell | grep -v grep | grep -v defunct | awk '{sum=sum+$6}; END {print sum/1024}'

228.57

Общий процент использования памяти для процессов с заданным именем:

$ ps -eo pmem,comm | grep chromium | awk '{sum+=$1} END {print sum " % of RAM"}'

67.5 % of RAM

$ ps -eo pmem,comm | grep apache2 | awk '{sum+=$1} END {print sum " % of RAM"}'

1.6 % of RAM

$ ps -eo pmem,comm | grep gnome-shell | awk '{sum+=$1} END {print sum " % of RAM"}'

7 % of RAM

Текущее использование памяти, включая использование SWAP, всеми активными процессами:

$ ps aux | awk '{sum+=$6} END {print sum/1024}'

3436.94


$ ps aux | awk '$11!~/\[*\]/ {print $6/1024" Mb --> "$11,$12}' | sort -g

Встроенные переменные

Утилита awk имеет ряд встроенных переменных, которые позволяют получить подробную информацию о входном потоке и настройках awk. Значения некоторых переменных можно изменять.  https://www.gnu.org/software/gawk/manual 

Переменные NF, NR и FILENAME

Представленная ниже команда позволяет быстро определить число записей(строк) во входном файле grade.txt. Значение переменной NR отображается по завершении обработки файла.

$ ~ awk 'END {print NR}' grade.txt

5

Текущий интерфейс:

$ route | grep -m1 ^default | awk '{print $NF}'

wlan0

В следующем примере на экран выводятся все записи исходного файла. Каждой из них предшествуют два числа: количество полей в записи (переменная NF) и номер записи в файле (переменная NR). В самом конце отображается имя входного файла (переменная FILENAME).

$ ~ awk '{print NF, NR, $0} END {print FILENAME}' grade.txt

7 1 M.Tansley 05/99 48311 Green 8 40 44

7 2 N.Lulu 06/99 48317 green 9 24 26

7 3 O.Bunny 02/99 48 Yellow 12 35 28

7 4 P.Troll 07/99 4842 Brown-3 12 26 26

7 5 Q.Tansley 05/99 4712 Brown-2 12 30 28

grade.txt

$ ~

Распечатать номера строк; awk '{print NR,$0}' например:

$ cat grade.txt | awk '{print NR,$0}'

1 M.Tansley:_05/99:_48311:_Green:_8:_40:_44

2 N.Lulu:_06/99:_48317:_green:_9:_24:_26

3 O.Bunny:_02/99:_48:_Yellow:_12:_35:_28

4 P.Troll:_07/99:_4842:_Brown-3:_12:_26:_26

5 Q.Tansley:_05/99:_4712:_Brown-2:_12:_30:_28

6 #:_разделитель:_<Space>

Переменную NF удобно использовать, когда требуется извлечь из путевого имени последнюю часть, т. е. имя файла или каталога. В этом случае необходимо указать, что разделителем полей является символ '/' и использовать ссылку $NF, которая является обозначением последнего поля текущей записи. Например:

$ ~ pwd

/home/iarch

$ ~ echo $PWD | awk -F/ '{print $NF}' 

iarch

$ ~

#Переменная среды $PWD хранит путевое имя текущего каталога.

OFMT   Формат распечатки чисел


Встроенная переменная OFMT содержит спецификацию формата по умолчанию, которую print использует с sprintf при превращении числа в цепочку символов для печати. Это значение OFMT равно "%.6g". 

OFMT позволяет использовать различные значения  в качестве спецификаций формата, ...можно менять форму чисел, печатаемых оператором print.

$ awk 'BEGIN {

> OFMT = "%.0f"    #будет округлять

> print 17.23, 17.54 }'

17 18

$ awk 'BEGIN { OFMT = "%.0f"; print 17.23, 17.54 }' 

17 18

https://www.gnu.org/OFMT.html 

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

$ calc() { awk 'BEGIN { OFMT="%f"; print "равно: "'"$*"'; exit}'; }

$ calc 2.4567 + 3.2345

равно: 5.691200

PS: Можно конечно поставить утилиту:

$ sudo apt-get install calc

$ calc 2.4567 + 3.2345

5.6912

$ ...но с функцией интересней, и глубину разряда можно регулировать.

Для математики лучше пользоваться Lua с ее библиотекой "math", Lua устанавливают наверное по умолчанию "везде":

$ lua -e "print (math.sin(12))"

-0.53657291800043

$ lua -e "print (math.cos(12))"

0.84385395873249

$ lua -e "print (2.4567 + 3.2345)"

5.6912

$ Lua

> = 1 + 2 + 4

7

> = 21 / 45

0.46666666666667

> ... великолепный калькулятор

Функция конвертации байтов в удобочитаемый размер файла:

$ human_filesize() { awk -v sum="$1" ' BEGIN {hum[1024^3]="Gb"; hum[1024^2]="Mb"; hum[1024]="Kb"; for (x=1024^3; x>=1024; x/=1024) { if (sum>=x) { printf "%.2f %s\n",sum/x,hum[x]; break; } } if (sum<1024) print "1kb"; } ';}

$ human_filesize 1234567890 

1.15 Gb

$ ...а можно пользоваться и утилитой numfmt

$ numfmt --to=iec-i <<< "1234567890" 

1.2Gi

$ numfmt --to=iec-i <<< "12345678907654323456" 

11Ei

$ human_filesize 12345678907654323456

11497809465.65 Gb

Извлечение строк


$ awk 'NR == 2' grade.txt

N.Lulu 06/99 48317 green 9 24 26


$ awk 'NR == 3' grade.txt

O.Bunny 02/99 48 Yellow 12 35 28

Комбинировать строки с полями:


$ awk 'NR == 3{print$1}' grade.txt

O.Bunny


$ awk 'NR == 3{print$2}' grade.txt

02/99


$ awk 'NR == 3{print$3}' grade.txt

48


$ awk 'NR == 3{print$4}' grade.txt

Yellow


$ awk 'NR == 3{print$5}' grade.txt

12


$ awk 'NR == 3{print$1 $4}' grade.txt

O.BunnyYellow 

Подставить в команду:

Например есть некий процесс:

$ ping 8.8.8.8

PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.

64 bytes from 8.8.8.8: icmp_seq=1 ttl=109 time=20.2 ms

64 bytes from 8.8.8.8: icmp_seq=2 ttl=109 time=17.2 ms

......................................................

 

$ ps aux | grep [p]ing  #[p]ing - убрать из вывода grep "grep"

dell        2546  0.0  0.0 309192  7740 ?   .....

dell        3122  3.7 10.8 3720148 868588 ? .....

dell       16659  0.0  0.0   7136 736 pts/0 ..ping 8.8.8.8

Узнаем его pid:

$ ps aux | grep [p]ing | awk 'NR == 3{print$2}'

16659

$

Выполнить, применив подстановку:

$ ps aux | grep [p]ing | kill -9 $(awk 'NR == 3{print$2}')

В итоге:

............................................................

64 bytes from 8.8.8.8: icmp_seq=128 ttl=109 time=18.2 ms

64 bytes from 8.8.8.8: icmp_seq=129 ttl=109 time=19.2 ms

Killed ... terminated by signal SIGKILL (Forced quit)

С использованием xargs:

$ ps aux | grep [p]ing | awk 'NR == 3{print$2}' | xargs -n 1 kill

$ Terminated

PS: Есть и "штатный" способ исключить из вывода "grep", это ключ -v самой утилиты:

$ ps aux | grep ping | grep -v grep

..........................................

$ ps aux | grep ping | grep -v grep | awk 'NR == 3{print$2}' | xargs -n 1 kill

$  Terminated

Проще не бывает:

$ ps -ef | grep [p]ing | awk '{print $2}' | xargs kill

$  Terminated

Для тех кому не нравиться AWK и Xargs. существует великолепная команды pkill, команда убивающая процесс по "патерну", синтаксис таков: pkill -f my_pattern например:

$ ping 8.8.8.8

PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.

64 bytes from 8.8.8.8: icmp_seq=1 ttl=104 time=34.6 ms

$ ps aux | grep [p]ing 

40160  0.0  0.0   7540  1116 pts/3    S+   13:09   0:00 ping 8.8.8.8

$ pkill -f ping

$......................................

64 bytes from 8.8.8.8: icmp_seq=121 ttl=104 time=33.4 ms

64 bytes from 8.8.8.8: icmp_seq=122 ttl=104 time=33.5 ms

Terminated

Lua - Стандартные арифметические операции:

"+" - сложение,

"-" - вычитание,

"/" - деление,

"*" - умножение,

"%" - остаток от деления (5%2 == 1).

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

GNU AWK / Built-in functions         9 Functions  /gawk/manual 

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

Функция gsub()

Благодаря функции gsub() вы сможете выполнить в текущей записи глобальную замену строк, соответствующих заданному регулярному выражению. Например, для изменения номера ученика с 4842 на 4899 введите такую команду:

$ ~ awk 'gsub(4842,4899) {print $0}' grade.txt

P.Troll 07/99 4899 Brown-3 12 26 26

$ ~

Функция index()

Чтобы узнать позицию первого вхождения подстроки t в строку s, воспользуйтесь функцией index (), только не забудьте взять ее аргументы в двойные кавычки, иначе они будут восприниматься как имена переменных среды. Например, следующая команда возвращает число, определяющее позицию подстроки "ny" в строке "Bunny":

$ ~ awk 'BEGIN {print index("Bunny","ny")}' grade.txt

4

$ ~

Функция length() 

Функция length() возвращает длину переданного ей текстового аргумента. В показанном ниже примере производится поиск информации об ученике с номером 4842, а затем определяется длина имени ученика:

$ ~ awk '$3==4842 {print length($1)" "$1}' grade.txt

7 P.Troll

$ ~

Следующая команда демонстрирует применение утилиты awk для вычисления длины текстовой строки:

$ ~ awk 'BEGIN {print length("A FEW GOOD MEN")}'

14

$ ~

Функция match()

Функция match() позволяет проверить, содержит ли строка заданную подстроку. Последняя может быть представлена как литералом в двойных кавычках, так и регулярным выражением. Если поиск прошел успешно, возвращается число, определяющее позицию, с которой начинается вхождение подстроки в искомую строку. В случае неудачи возвращается ноль. Следующая команда проверяет, содержит ли имя ученика с номером 48317 символ 'u':

$ ~ awk '$3==48317 {print match ($1, "u"), $1} ' grade.txt

4 N.Lulu

$ ~

Функция split()

Функция split() преобразует переданную ей строку в массив и возвращает число элементов в полученном массиве. В следующем примере заданная строка разбивается на три элемента, которые помещаются в массив myarray. Разделителем элементов в данном случае является символ '#'.

$ ~ awk 'BEGIN {print split("123#456#678", myarray,"#")}'

3

$ ~

Массив myarray будет иметь такую структуру:

mуarray[1]="123" 

myarray[2]="456"

myarray[3]="678"

Функция sub()

Функция sub() применяется для поиска строки, соответствующей заданному шаблону, и ее замены при первом появлении. В этом состоит отличие данной функции от функции gsub(), которая находит все случаи вхождения подстроки в строку, производя соответствующее число замен. Приведенная ниже команда находит запись ученика P. Troll и меняет его рейтинг с 26 на 29 (поле 6), при этом значение поля 7 (тоже 26) остается неизменным:

$ ~ awk '$1=="P.Troll" {sub(26,29,$0)} {print $0}' grade.txt

M.Tansley 05/99 48311 Green 8 40 44

N.Lulu 06/99 48317 green 9 24 26

O.Bunny 02/99 48 Yellow 12 35 28

P.Troll 07/99 4842 Brown-3 12 29 26

Q.Tansley 05/99 4712 Brown-2 12 30 28

Исключить строку:

$ awk '{sub("O.Bunny","")}1' grade.txt

M.Tansley 05/99 48311 Green 8 40 44

N.Lulu 06/99 48317 green 9 24 26

 02/99 48 Yellow 12 35 28

P.Troll 07/99 4842 Brown-3 12 26 26O

Q.Tansley 05/99 4712 Brown-2 12 30 28

Вернуть:

$ awk '$1=="O.Bunny" {print substr($1,1,7)}1' grade.txt

M.Tansley 05/99 48311 Green 8 40 44

N.Lulu 06/99 48317 green 9 24 26

O.Bunny

O.Bunny 02/99 48 Yellow 12 35 28

P.Troll 07/99 4842 Brown-3 12 26 26O

Q.Tansley 05/99 4712 Brown-2 12 30 28

Зачем нужен символ "1" в конце инструкции?: awk оценивает "1" как истину и по умолчанию печатает всю строку, включая новую строку.

$ echo 'foo' | awk '/foo/{print}1'

foo

foo


Функция substr()

Функция substr() возвращает указанную часть строки. Вам нужно задать позицию, с которой начинается вхождение подстроки в искомую строку, и длину подстроки. Рассмотрим пример:

$ ~ awk '$1=="M.Tansley" {print substr($1,1,5)}' grade.txt

M.Tan

$ ~

Эта команда возвращает из строки "M. Tansley" подстроку, начинающуюся с первого символа и занимающую пять символов.

Если значение третьего аргумента значительно превышает реальную длину строки, функция substr () возвращает все символы строки, начиная с указанной позиции:

$ ~ awk '$1=="M.Tansley" {print substr ($1,3, 99)} ' grade.txt

Tansley

$ ~

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

$ ~ awk '{print substr($1,3)}' grade.txt

Tansley

Lulu

Bunny

Troll

Tansley

$ ~

Awk/example/substring-extraction 

Передача строк из интерпретатора shell утилите awk

Очень часто утилита awk получает входные данные не из файла, а по каналу (pipe"|") от других команд. Рассмотрим несколько примеров обработки строк, поступающих из канала. В первом примере команда echo передает строку "Stand‑by" утилите awk, которая вычисляет ее длину:

$ ~ echo "Stand‑by" | awk '{print length($0)}'

8

$ ~

Во втором примере утилита awk получает строку с именем файла и возвращает имя файла без расширения:

$ ~ echo "mydoc.txt" | awk '{print substr($STR,1,5)}'

mydoc

$ ~

Следующая команда возвращает только расширение файла:

$ ~ echo "mydoc.txt" | awk '{print substr($STR,7)}'

txt

$ ~

Escape–последовательности 

При работе со строками и регулярными выражениями нередки случаи включения в шаблон поиска непечатаемых символов (таких как символ новой строки либо табуляции) или же символов со специальным значением в утилите awk (любой из метасимволов). Такие символы создаются с помощью управляющих Escape–последовательностей, признаком которых является обратный слеш в начале. Например, шаблон поиска открывающей фигурной скобки выглядит так:     /\|/

Escape–последовательности утилиты awk:

В следующей команде сначала отображается фраза "May Day", в которой слова разделены символом табуляции, а затем выводятся два символа новой строки, вследствие чего образуется пустая строка. Потом отображается слово "May", а за ним cлово "Day", каждая буква которого представлена  ASCII–кодом: 'D' - 104, 'а'- 141,'у'- 171.

$ ~ awk 'BEGIN {print "May\tDay\n\nMay \104\141\171"}'

May     Day


May Day

$ ~

Команда printf

Во всех примерах, с которыми мы ознакомились, данные выводились на экран с помощью команды print без какого‑либо форматирования. В awk имеется намного более мощная команда printf, аналог одноименной функции языка С, позволяющая задавать правила форматирования выходных данных. В Linux это встроенная команда оболочки, аналог echo, с более замысловатым синтаксисом и более широкими возможностями (aidalinux.ru/w/Printf):

$ type -a printf

printf is a shell builtin

printf is /usr/bin/printf

Базовый синтаксис команды таков:  printf "строка_формaтирования", аргументы

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

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

В состав спецификаторов форматирования могут входить различные модификаторы, определяющие дополнительные особенности форматирования. Модификатор помещается между символом '%' и управляющим символом.

Дополнительные модификаторы:

Преобразование символов

Чтобы узнать, ASCII–код какого символа равен 65, можно с помощью команды echo направить строку "65" утилите awk и затем передать ее в качестве аргумента команде printf со спецификатором %с. Команда printf выполнит преобразование автоматически:

$ ~ echo "65" | awk '{printf "%c\n", $0}'

A

$ ~

Как видите, это символ 'A'. Обратите внимание на наличие в команде символа новой строки (\n). Необходимость в нем объясняется тем, что команда printf по умолчанию не записывает этот символ в выходной поток. Если не указать Escape–последовательность \n, сразу после буквы 'А' в той же строке будет отображено приглашение интерпретатора shell, что может смутить пользователя, работающего в данный момент за терминалом. Конечно, код символа может быть указан непосредственно в команде printf:

$ ~ awk 'BEGIN {printf "%c\n", 65}'

A

$ ~ awk 'BEGIN {printf "%c\n", 66}'

B

$ ~ awk 'BEGIN {printf "%c\n", 67}'

C

$ ~


От десятичного:

$ awk 'BEGIN {printf "%c\n", 33}'

!

$ awk 'BEGIN {printf "%c\n", 36}'

$

$ awk 'BEGIN {printf "%c\n", 37}'

%

От "hex"

$ awk 'BEGIN {print "\x21"}'

!

$ awk 'BEGIN {print "\x24"}'

$

$ awk 'BEGIN {print "\x25"}'

%

От восьмиричного:

$ awk 'BEGIN {print "\041"}'

!

$ awk 'BEGIN {print "\044"}'

$

$ awk 'BEGIN {print "\045"}'

%


Обратно, воспользовавшись ord:

$ echo "!" | awk 'BEGIN{for(n=0;n<256;n++)ord[sprintf("%c",n)]=n}{print ord[$1]}'

33

$ echo "$" | awk 'BEGIN{for(n=0;n<256;n++)ord[sprintf("%c",n)]=n}{print ord[$1]}'

36

$ echo "%" | awk 'BEGIN{for(n=0;n<256;n++)ord[sprintf("%c",n)]=n}{print ord[$1]}'

37

Используя printf (форматированный вывод), аналог одноименной функции языка С в Linux это встроенная команда оболочки:

$ type -a printf

printf is a shell builtin

printf is /usr/bin/printf


$ printf "%d\n"  "'!"

33 # десятичное

$ printf "%o\n"  "'!"

41 # восьмиричное

$ printf "%x\n"  "'!"

21 # "hex"

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

Предположим, необходимо отобразить имена учеников и их идентификаторы, причем имена должны быть выровнены по левому краю и размещаться в поле длиной 15 символов. В конце строки форматирования стоит символ новой строки (\n), служащий для разделения записей. Выводимые данные будут размещаться в двух колонках:

$ ~ awk '{printf "%-15s %d\n", $1, $3}' grade.txt

M.Tansley       48311

N.Lulu          48317

O.Bunny         48

P.Troll         4842

Q.Tansley       4712

$ ~

Передача переменных утилите awk

Переменные можно создавать не только в сценарии awk, но и непосредственно в командной строке. Формат вызова утилиты awk в этом случае таков:

awk 'сценарий' переменная=значение входной_файл

В следующем примере переменная AGE создается в командной строке и инициализируется значением 10. Показанная команда находит студентов, возраст которых не превышает 10 лет.

$ ~ awk '{if($5 < AGE) print $0}' AGE=10 grade.txt

M.Tansley 05/99 48311 Green 8 40 44

N.Lulu 06/99 48317 green 9 24 26

$ ~

Рассмотрим более сложный пример. Системная команда df отображает информацию о смонтированных файловых системах. Опция [- к] команды df устанавливает размер блока равным 1 Кб (что наиболее привычно).  Результаты ее работы по умолчанию имеют следующий формат:

# df -k

Файловая система     1K-блоков      Использовано      Доступно   Использовано%   Cмонтировано в

dev                                   505636                             0      505636                            0%        /dev

run                                   509256                         736       508520                           1%     /run

/dev/sda1                        20511356              11614800     7831596                          60%    /

tmpfs                               509256                             4       509252                             1%    /dev/shm

tmpfs                               509256                             0       509256                            0%    /sys/fs/cgroup

tmpfs                               509256                            36      509220                             1%    /tmp

/dev/sda2                        38057472              30873968    5227256                          86%    /home

/dev/sda3                        19091584               13087876   5010788                          73%    /mnt/Debian

/dev/sda4                        17964924              10753644    6275652                         64%   /mnt/Kali

tmpfs                               101848                             0       101848                             0%   /run/user/0

tmpfs                               101848                           20       101828                             1%   /run/user/1000

#

# cd /

# du -h --max-depth=1

286G ./media

8,0K ./mnt

77G ./Data

..........

# cd /var

# du -h --max-depth=1

156M ./cache

2,0M ./NX

...............

Чтобы узнать, в какой из имеющихся файловых систем объем свободного пространства ниже критической отметки, следует передать выходные данные команды df утилите awk и последовательно сравнить значения в четвертом столбце с пороговым значением. В следующей командной строке пороговое число задано в виде переменной TRIGGER, которая равна 5000000 - 5G:

# df -k | awk '$4 ~ /^[0-9]/ {if($4 < TRIGGER) print $1"\t"$4}' TRIGGER=5000000

dev     505636

run     508520

tmpfs   509252

tmpfs   509256

tmpfs   509220

tmpfs   101848

tmpfs   101828

$ ~

Проверка $4 ~ /^[0-9]/ позволяет отсечь заголовок отчета команды df, содержащий в четвертом столбце строку "Доступно".

Разделы использующие более 50%(или сколько надо) дискового пространства:

$ df -h |awk '{a=$5;gsub(/%/,"",a);if(a > 50){print $0}}' 

Filesystem      Size  Used Avail Use% Mounted on

/dev/sda10       77G   61G   12G  85% /Data

/dev/sda5       124G  106G   12G  90% /Share

Вот еще один пример. Команда who выводит сведения о пользователях, зарегистрировавшихся в системе. В первом столбце выходных данных этой команды отображаются регистрационные имена пользователей, а во втором — имена терминалов, к которым подключены эти пользователи. С помощью утилиты awk вы можете отфильтровать результаты работы команды who и узнать к какому терминалу подключены: ,

$ ~  who

iarch    tty1         2017-05-07 13:49

iarch    pts/0        2017-05-08 15:20 (192.168.1.100)

$ ~  who | awk '{if($1==user) print $1 " you are connected to " $2}' user=$LOGNAME

iarch you are connected to tty1

iarch you are connected to pts/0

$ ~

Здесь локальная переменная user инициализируется значением переменой среды $LOGNAME, которая хранит регистрационное имя текущего пользователя.

Файлы сценариев

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

$ ~ awk 'tot+=$6; END {print "Club student total points; " tot}' grade.txt

M.Tansley 05/99 48311 Green 8 40 44

N.Lulu 06/99 48317 green 9 24 26

O.Bunny 02/99 48 Yellow 12 35 28

P.Troll 07/99 4842 Brown-3 12 26 26

Q.Tansley 05/99 4712 Brown-2 12 30 28

Club student total points; 155

$ ~

Создадим на ее основе файл, который назовем student_tot.awk. Расширение awk является общепринятым соглашением относительно именования файлов сценариев awk. Вот текст этого файла:

$ ~ cat > student_tot.awk

#!/bin/awk -f #Чаще #!/usr/bin/awk -f: $ type awk:  awk is /usr/bin/awk

#Все строки комментариев должны начинаться с символа '#'

#Имя файла: student_tot.awk

#Командная строка: student_tot.awk grade.txt

#Вычисление суммарного и среднего рейтинга учеников секции.

#Сначала выводим заголовок.

BEGIN {

print "Student Date Member   Grade Age Points Max"

print "Name joined                   Gained point available"

print "============================================="

}

# Суммируем рейтинг учеников.

(tot+=$6)

# В завершение выводим суммарный и средний рейтинг.

END {

print "Общий балл студенческого клуба:" tot

print "Средние баллы студенческого клуба:" tot/NR

}

^C

$ ~

В этом сценарии мы формируем заголовок отчета и вычисляем не только суммарный рейтинг, но и средний рейтинг учеников секции, который получается путем деления переменной tot на переменную NR, содержащую число записей во входном файле. Как видите, на языке awk можно писать полноценные программы, содержащие команды, комментарии, а также пустые строки и дополнительные пробелы, предназначенные для повышения удобочитаемости текста сценария.

Ключевым моментом сценария является первая строка, выглядящая как комментарий: #!/bin/awk -f

Это своеобразная системная инструкция с названием  shebang, указывающая, какая программа должна выполнять данный сценарий. Подобная инструкция должна быть первой строкой любого сценария. Шебанг  (shebang, sha-bang, hashbang, pound-bang, or hash-pling) — в программировании последовательность из двух символов: решётки и восклицательного знака ("#!") в начале файла скрипта. Общий ее формат таков: #!/путь/программа [командная_строка]

Когда происходит запуск исполняемого файла, система проверяет, начинается ли он с "магической" последовательности. Если нет, значит, файл содержит машинные коды и выполняется непосредственно. Если же обнаружено выражение #!, то это файл сценария. В таком случае происходит следующее:

В нашем случае это означает, что при запуске сценария вместо команды

$ student_tot.awk grade.txt

в действительности выполняется такая команда:

$ /bin/awk -f student_tot.awk grade.txt

Опция -f утилиты awk говорит о том, что выполняемые команды находятся в указанном вслед за ней файле.

После создания файл student_tot.awk необходимо сделать его исполняемым с помощью команды

$ chmod +x student_tot.awk  или chmod 744 student_tot.awk

Ну и все остальное,....стоит добавить, что есть более "магическая" запись, это  ./ - точка слэш, позволяющая выполнение исполняемого файла из любой дирректории, не обращая внимание на переменую $PATH.

И вот результаты работы сценария:

$ ~ ./student_tot.awk grade.txt

Student Date Member   Grade Age Points Max

Name joined                    Gained point available

=============================================

M.Tansley 05/99 48311 Green 8 40 44

N.Lulu 06/99 48317 green 9 24 26

O.Bunny 02/99 48 Yellow 12 35 28

P.Troll 07/99 4842 Brown-3 12 26 26

Q.Tansley 05/99 4712 Brown-2 12 30 28

Общий балл студенческого клуба:155

Средние баллы студенческого клуба:31

$ ~

Использование переменной FS в сценариях awk

Если просматривается файл, в котором разделителем полей является символ, отличный от пробела, например '#' или ':', это легко учесть, указав в командной строке опцию ' -F:'

$ awk -F: '{print $0}' входной_файл

Аналогичную функцию выполняет переменная FS, которую можно установить непосредственно в сценарии. Следующий сценарий обрабатывает файл /etc/passwd, выводя на экран содержимое первого и пятого полей, включающих соответственно имя пользователя и описание роли пользователя в системе. Поля в этом файле разделены символом двоеточия, поэтому в процедурной части шаблона begin устанавливается переменная FS, значение которой заключается в двойные кавычки:

$ ~ cat > passwd.awk

#!/usr/bin/awk -f

# Имя файла: student_tot.awk

# Командная строка: passwd.awk /etc/passwd

# Вывод содержимого первого и пятого полей файла passwd.

BEGIN {

FS=":" 

}

{print $1"\t"$5}

^C

$ ~

$ ~ chmod 744 passwd.awk (chmod +x passwd.awk)

$ ~

Вот возможные результаты работы этого сценария:

$ ~ ./passwd.awk /etc/passwd

root    root

bin     bin

daemon  daemon

mail    mail

ftp     ftp

http    http

uuidd   uuidd

dbus    dbus

nobody  nobody

................

...............

$ ~

Передача переменных сценариям awk 

При передаче переменной сценарию awk формат командной строки таков:

awk файл_сценария переменная=значение входной_файл

Следующий небольшой сценарий сравнивает количество полей в каждой записи входного файла с заданным в командной строке значением. Текущее количество полей хранится в переменной NF. Сравниваемое значение передается сценарию в виде переменной МАХ.

$ cat > fieldcheck.awk

#!/usr/bin/awk -f

#Имя файла: fieldcheck.awk

#Командная строка: fieldcheck.awk MAX=n [FS=<разделитель>] имя_файла

#Проверка числа полей в записях файла.

NF!=MAX{

print("line " NR " does not have " MAX " fields")}

$ ~ chmod +x fieldcheck.awk

Файл /etc/passwd, содержит семь полей с разделителем ":", указав другое значение получим  ("line " NR " does not have " MAX " fields"):

$ ./fieldcheck.awk MAX=7 FS=":" /etc/passwd

$

$ ./fieldcheck.awk MAX=6 FS=":" /etc/passwd

line 1 does not have 6 fields

line 2 does not have 6 fields

line 3 does not have 6 fields

........................

line 61 does not have 6 fields

line 62 does not have 6 fields

Следующий сценарий выводит информацию об учениках, чей возраст ниже значения, заданного в командной строке:

cat > age.awk

#!/usr/bin/awk -f

# Имя файла: age.awk

# Командная строка: age.awk AGE=n grade.txt

# Вывод информации об учениках, чей возраст ниже заданного,

{if($5 < AGE) print $0}

^C

$ ~ chmod +x age.awk

$ ~ ./age.awk AGE=10 grade.txt

M.Tansley 05/99 48311 Green 8 40 44

N.Lulu 06/99 48317 green 9 24 26

$ ~

Массивы

Изучая функцию split(), мы говорили о том, каким образом ее можно использовать для преобразования строки символов в массив. Повторим соответствующий пример:

$ ~ awk 'BEGIN {print split("123#456#678", myarray, "#")}'

3

$ ~

Функция split() возвращает число элементов созданного массива myarray. Внутренняя структура массива myarray в этом случае такова:

myarray[1]="123"

myаrray[2]="456"

myarray[3]="678"

При работе с массивами в awk не требуется заранее их объявлять. Не нужно также указывать количество элементов массива. Для доступа к массиву обычно применяется цикл for, синтаксис которого следующий: for (элемент in массив) print массив[элемент]

В показанном ниже сценарии функция split() разбивает заданную строку на элементы и записывает их в массив myarray, а в цикле for содержимое массива выводится на экран:

$ ~ cat > arraytest.awk

#!/usr/bin/awk -f

#Имя файла: arraytest.awk

#Командная строка: arraytest.awk /dev/null

#Вывод элементов массива.

BEGIN {

record="l23#456#789";

split(record, myarray, "#") }

END {

for (i in myarray) print myarray[i]

}

^C

$ ~ chmod 744 arraytest.awk

$ ~ ./arraytest.awk /dev/null

l23

456

789

$ ~

Для запуска сценария в качестве входного файла следует указать устройство /dev/null. Если этого не сделать, утилита awk будет ожидать поступления данных с клавиатуры.

Статические массивы

В предыдущем примере массив формировался динамически. Следующий пример является более сложным и демонстрирует, как создавать в сценарии статические массивы. Ниже показан входной файл grade_student.txt, включающий информацию об учениках нашей секции каратистов. Записи файла содержат два поля: первое — название пояса, которым владеет ученик, второе — категория ученика (взрослый, юниор). Разделителем полей служит символ '#'.

$ ~ cat > grade_student.txt

Vellow#Junior

Orange#Senior

Yellow#Junior

Purple#Junior

Brown-2#Junior

White#Senior

Drange#Senior

Red#Junior

Brown-2#Senior

Yellow#Senior

Red#Junior

Blue#Senior

Green#Senior

Purple#Junior

White#Junior 

^C

$ ~

Наша задача заключается в том, чтобы прочитать файл и получить следующие сведения:

1.Сколько учеников имеют желтый, оранжевый и красный пояса?

2.Сколько взрослых и детей посещают секцию?

Рассмотрим такой сценарий:

$ ~ cat >belts.awk

#!/usr/bin/awk -f

#Имя файла: belts.awk

#Командная строка: belts.awk grade_student.txt

#Подсчет числа учеников, имеющих желтый, оранжевый и красный пояса,

#а также количества взрослых и юных членов секции.

# Задание разделителя и создание массивов.

BEGIN {FS="#"

# Создание массива, индексами которого являются названия поясов

belt["Yellow"]

belt["Orange"]

belt["Red"]

#Создание массива, индексами которого являются названия категорий учеников

student["Junior"]

student["Senior"]

}

#Если значение первого поля совпадает с индексом массива belt,

#содержимое соответствующего элемента массива увеличивается на единицу

{for(colour in belt)

{if ($1==colour)

belt[colour]++}}

# Если значение второго поля совпадает с индексом массива student

# содержимое соответствующего элемента массива увеличивается на единицу

{for (senior_or_junior in student)

{if ($2==senior_or_junior)

student [senior_or_junior] ++}}

# Вывод полученных результатов

END {for (colour in belt)

print "The club has ", belt[colour],colour,"Belts"

print "*******************************"

for (senior_or_junior in student) print "The club has",\

student[senior_or_junior],senior_or_junior,"students"

}

^C

$ ~

$ ~ chmod +x belts.awk

$ ~

В процедурной части шаблона begin в переменную FS записывается символ '#" - pазделитель полей во входном файле. Затем создаются два массива, belt и student, индексами которых являются соответственно названия поясов и названия категорий учеников. Оба массива остаются не инициа-лизированными, их тип не определен.

В первом цикле for значение первого поля каждой записи входного файла сравнивается с названием индекса массива belt (индекс равен "Yellow", "Orange" или "Red"). Если обнаруживается совпадение, выполняется приращение элемента, хранящегося в массиве по этому индексу. Поскольку операция ++ (инкремент) определена для целочисленных значений, утилита awk считает, что массив целочисленный, и инициализирует его элементы значением 0.

Во втором цикле for значение второго поля сравнивается с названием индекса массива student (индекс равен "Junior" или "Senior"). Результат операции вычисляется так же, как и в первом цикле.

В процедурной части шаблона END осуществляется вывод итоговых результатов. Итого:

$ ~ ./belts.awk grade_student.txt

The club has  2 Red Belts

The club has  1 Orange Belts

The club has  2 Yellow Belts

**************************

The club has 7 Senior students

The club has 7 Junior students

$ ~

 Язык программирования awk может показаться сложным для изучения, но если осваивать его на примерах употребления отдельных команд и небольших сценариев, то процесс обучения не будет слишком трудным. Утилита awk является важным инструментом shell–программирования, и чтобы применять ее, вам не обязательно быть экспертом по языку awk.

The_AWK_Programming_Language.pdf
Sed & Awk.pdf
AWK cheat sheets.pdf
The AWK Manual.pdf
GAWK: Effective AWK Programming.pdf

SED

Работа с редактором sed

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

Чтение и обработка данных в sed

Общая схема работы редактора sed такова:

Вызов редактора sed

Вызвать редактор sed можно тремя способами:


Как и в awk, не забудьте заключить команды в одинарные кавычки, чтобы защитить от интерпрета-ции находящиеся в них специальные символы.

Когда входной файл не указан, sed будет ожидать поступления данных из стандартного входного потока: с клавиатуры или из канала.

Ниже перечислены основные опции редактора sed и описано их назначение:

Сохранение выходных данных

Если требуется сохранить проделанные изменения, просто перенаправьте результаты работы редактора sed в файл стандартным оператором перенаправления вывода, например так : $ sed 'команды' входной_файл > выходной_файл

Синтаксис команд

Общий синтаксис команд редактора sed таков: 

[адрес1 [, адрес2] ] [ ! ] команда [аргументы]

Команда состоит из одной буквы или одного символа (Список основных команд представлен ниже). Аргументы требуются лишь нескольким командам, в частности, команде s. Элементы, представлен-ные в квадратных скобках, являются необязательными, а сами скобки набирать не нужно.

Просмотр входного файла по умолчанию начинается с первой строки. Существует два способа адресации строк:

В команде может быть указано два адреса, один адрес или ни одного адреса. В следующей таблице описаны все возможные правила отбора строк в зависимости от того, сколько компонентов адреса задано. Некоторые команды, в частности, a, i, r, q и =, требуют указания только одного адреса.

Правила отбора строк в редакторе sed:

Основные команды редактирования

Ниже представлен список основных команд, имеющихся в редакторе sed. Основные команды sed:

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

[адрес1[, адрес2]]{ 

команда 1

....................

команда n

}

или

[адрес1[,адрес2]] {команда1; …командаN; }

В первом случае каждая команда записывается в отдельной строке, а разделителем команд является символ новой строки. Во втором случае команды записываются последовательно, отделяясь друг от друга точкой с запятой, которая ставится также после завершающей команды. Ниже приведен текстовый файл quote.txt, который  будет использоваться во многих примерах ниже:

$ ~ cat > quote.txt

The honeysuckle band played all night long for only $90.

It was an evening of splendid music and company.

Too bad the disco floor fell through at 23:10.

The local nurse Miss P. Neave was in attendance.

^C

$ ~

Регулярные выражения

Редактор sed распознает базовые регулярные выражения. Дополнительные особенности появляются только в шаблонах поиска и замены в команде s. С помощью операторов \ ( и \) можно сохранить до девяти шаблонов поиска во временном буфере, с тем чтобы в шаблоне замены обратиться к ним с помощью оператора \n, где n — номер сохраненного шаблона. Метасимвол & позволяет в шаблоне замены сослаться на фрагмент строки, соответствующий шаблону поиска.

Вывод строк (команда p)

Рассмотрим, как в редакторе sed осуществляется поиск строк и вывод их на экран.

Отображение строки по номеру

Команда p (print) имеет такой формат: 

[адрес1[,адрес2]]p

Для отображения строки входного файла достаточно указать ее номер, например:

$ ~ sed '2p' quote.txt

The honeysuckle band played all night long for only $90.

It was an evening of splendid music and company.

It was an evening of splendid music and company.

Too bad the disco floor fell through at 23:10.

The local nurse Miss P. Neave was in attendance.

$ ~

Что было сделано неправильно? Ведь требовалось отобразить только строку номер 2, однако в результате были выведены на экран все строки файла, причем вторая строка — дважды. Причина подобного поведения заключается в том, что по умолчанию редактор sed отображает каждую просматриваемую строку. Чтобы избежать этого, воспользуемся опцией -n:

$ ~ sed -n '2p' quote.txt

It was an evening of splendid music and company.

$ ~

Поиск специальных символов

Если требуется найти строку, содержащую символ '$', который в редакторе sed имеет специальное назначение, следует защитить этот символ от интерпретации с помощью обратной косой черты, как показано ниже:

$ ~ sed -n '/\$/ p' quote.txt

The honeysuckle band played all night long for only $90.

$ ~

Поиск первой строки

Для вывода первой строки входного файла достаточно указать ее номер:

$ ~ sed -n '1p' quote.txt

The honeysuckle band played all night long for only $90.

$ ~

Вывод номеров строк (команда =)

Команда = имеет следующий формат:  [адрес] =

Она предназначена для вывода номера строки, соответствующей заданному адресу. Рассмотрим пример:

$ ~ sed '/music/=' quote.txt

The honeysuckle band played all night long for only $90.

2

It was an evening of splendid music and company.

Too bad the disco floor fell through at 23:10.

The local nurse Miss P. Neave was in attendance.

$ ~

В данном случае отображается весь файл, причем перед строкой, содержащей слово "music", выводится ее номер. Из этого можно сделать заключение, что команда = выполняется перед тем, как текущая строка будет выведена на экран. Если же требуется узнать только номер строки, задайте опцию -n:

$ ~ sed -n '/music/=' quote.txt

2

$ ~

Можно также отобразить и строку, и ее номер. Для этого следует воспользоваться опцией -e, позволяющей указать несколько команд подряд. Первая команда выводит строку, в которой найдено совпадение с шаблоном, а вторая — номер этой строки:

$ ~ sed -n -e '/music/p' -e '/music/=' quote.txt

It was an evening of splendid music and company.

2

$ ~

Отображение строк из заданного диапазона

Предположим, требуется вывести строки с номерами от 1 до 3. В этом случае следует указать два адреса, разделенные запятой:

$ ~ sed -n '1,3p' quote.txt

The honeysuckle band played all night long for only $90.

It was an evening of splendid music and company.

Too bad the disco floor fell through at 23:10.

$ ~

Поиск строк, соответствующих шаблону

В следующем примере показано, как найти строку, содержащую слово "Neave":

$ ~ sed -n '/Neave/p' quote.txt

The local nurse Miss P. Neave was in attendance.

$ ~

Поиск пo шаблону и номеру строки

Если адрес представлен в виде шаблона, редактор sed находит все строки, соответствующие этому шаблону. Как можно уточнить местонахождение строки? 

Рассмотрим пример. Предположим, требуется найти слово "The" в последней строке файла quote.txt. Если воспользоваться поиском по шаблону, то будет получено две строки:

$ ~ sed -n '/The/p' quote.txt

The honeysuckle band played all night long for only $90.

The local nurse Miss P. Neave was in attendance.

$ ~

Чтобы остановить свой выбор на последней строке, следует указать ее номер перед шаблоном:

$ ~ sed -n '4,/The/p' quote.txt

The local nurse Miss P. Neave was in attendance.

$ ~

Поиск последней строки

Чтобы сослаться на последнюю строку входного файла, воспользуйтесь метасимволом '$':

$ ~ sed -n '$p' quote.txt

The local nurse Miss P. Neave was in attendance.

$ ~

Отображение всего файла

Если требуется отобразить весь файл, задайте диапазон строк от первой до последней:

$ ~ sed -n '1,$p' quote.txt

The honeysuckle band played all night long for only $90.

It was an evening of splendid music and company.

Too bad the disco floor fell through at 23:10.

The local nurse Miss P. Neave was in attendance.

$ ~

Добавление текста (команда а)

Для добавления текста предназначена команда a (append), которая вставляет одну или несколько строк текста после адресуемой строки. Формат команды таков:

[адрес] a\

текст\

текст\

..........

текст

Адрес может быть представлен в виде номера строки либо регулярного выражения. Во втором случае найденных строк может быть несколько. При добавлении текста отсутствует возможность задать диапазон строк. Допускается указание только одного шаблона адреса. Если адрес, по которому помещается текст, не указан, тогда команда будет применена к каждой строке входного файла.

Обратите внимание на присутствие символа обратной косой черты в конце каждой добавляемой строки, а также после самой команды а. Этот метасимвол защищает от интерпретации символ новой строки. В последней строке указывать обратную косую черту не требуется, поскольку концевой символ новой строки в этом случае является признаком конца команды.

Добавляемый текст записывается в стандартный выходной поток и не дублируется во входном буфере, поэтому не подлежит редактированию, т. е. на него нельзя сослаться в последующих шаблонах поиска. Чтобы иметь возможность отредактировать полученный текст, необходимо сохранить результаты работы редактора sed в новом файле и применить команды редактирования уже к нему.

Создание файла сценария

Конечно, ввод многострочных команд в режиме командной строки не слишком удобен и чреват ошибками, поэтому лучше всего размещать такие команды в файлах сценариев. Кроме того, в сценариях допускается наличие пустых строк и комментариев, что облегчает восприятие самих сценариев. Создадим новый файл с именем append.sed и добавим в него показанные ниже команды:

$ ~ cat > append.sed

#!/bin/sed -f

/company/a\

Then suddenly it happened.

^C

$ ~

Сделаем этот файл исполняемым:

$ chmod +x append.sed  или chmod 744 append.sed

Выполненим:

$ ~ ./append.sed quote.txt

The honeysuckle band played all night long for only $90.

It was an evening of splendid music and company.

Then suddenly it happened.

Too bad the disco floor fell through at 23:10.

The local nurse Miss P. Neave was in attendance.

$ ~

Рассмотрим, что делает сценарий append.sed. Первая его строка является системной командой, которая указывает, какая программа выполняет данный сценарий. Формат этой команды мы уже рассматривали при знакомстве с файлами сценариев awk выше. Редактор sed, как правило, находится в каталоге /bin, в современных Linux он в добавок еще и хеширован:

$ type sed

sed is hashed (/bin/sed)

$ hash -l

builtin hash -p /usr/bin/figlet figlet

builtin hash -p /usr/bin/tput tput

builtin hash -p /bin/date date

builtin hash -p /bin/cat cat

builtin hash -p /bin/sed sed

 Далее в сценарии находится команда а, которая ищет во входном файле строку, содержащую слово "company", и вставляет после нее предложение: Then suddenly it happened.

Вставка текста (команда i)

Команда i (insert) аналогична команде а, только вставляет текст не после, а перед адресуемой строкой. Как и при добавлении текста, допускается указание только одного шаблона адреса. Ниже приведен общий формат команды:

[адрес] i\

текст\ 

текст\

.........

текст

В следующем сценарии предложение "Utter contusion followed" вставляется перед строкой, содержащей слово "attendance":

$ ~ cat > insert.sed

#! /bin/sed -f

/attendance/i\

Utter confusion followed.

^C

$ ~ chmod 744 insert.sed

$ ~

Результаты работы данного сценария будут такими:

$ ~ cat quote.txt

The honeysuckle band played all night long for only $90.

It was an evening of splendid music and company.

Too bad the disco floor fell through at 23:10.

The local nurse Miss P. Neave was in attendance.

$ ~ ./insert.sed quote.txt

The honeysuckle band played all night long for only $90.

It was an evening of splendid music and company.

Too bad the disco floor fell through at 23:10.

Utter confusion followed.

The local nurse Miss P. Neave was in attendance.

$ ~

Для указания места вставки текста можно было бы воспользоваться номером строки, здесь 4:

#!/bin/sed -f

4i\

Utter confusion followed.

Удаление текста (команда d)

Для удаления текста предназначена команда d (delete), имеющая следующий формат:

[адрес1[, адрес2]] d

Адрес может быть указан в виде номера строки или регулярного выражения. Рассмотрим примеры. В первом из них будет удалена первая строка входного файла:

$ ~ sed '1d' quote.txt

It was an evening of splendid music and company.

Too bad the disco floor fell through at 23:10.

The local nurse Miss P. Neave was in attendance.

$ ~

В следующем примере удаляются строки 1—3:

$ ~ sed '1,3d' quote.txt

The local nurse Miss P. Neave was in attendance.

$ ~

В этом примере удаляется последняя строка:

$ ~ sed '$d' quote.txt

The honeysuckle band played all night long for only $90.

It was an evening of splendid music and company.

Too bad the disco floor fell through at 23:10.

$ ~

Можно также удалить строку, в которой найдено совпадение с регулярным выражением. В показанном ниже примере удаляется строка, содержащая слово '"Neave":

$ ~  sed '/Neave/d' quote.txt

The honeysuckle band played all night long for only $90.

It was an evening of splendid music and company.

Too bad the disco floor fell through at 23:10.

$ ~

Изменение текста (команда с)

Команда с (change) заменяет новым текстом каждую адресуемую строку. Если выбрана группа строк, вся группа заменяется одной копией текста. Формат команды с таков:

[адрес1[,адрес2]] c\ 

текст\

текст\

..........

текст

В следующем примере первая строга файла quote.txt заменяется новой строкой:

$ ~ cat > change.sed

#! /bin/sed -f

1c\

The Office Dibble band played well.

^C

$ ~ chmod 744 change.sed

$ ~

Итого:

$ ~ ./change.sed quote.txt

The Office Dibble band played well.

It was an evening of splendid music and company.

Too bad the disco floor fell through at 23:10.

The local nurse Miss P. Neave was in attendance.

$ ~

Команды изменения, добавления и вставки текста можно применять к одному и тому же файлу. Ниже приведен пример такого сценария, снабженный необходимыми комментариями:

$ ~ cat > mix.sed

#! /bin/sed -f

# Изменяем строку номер 1

1c\

The Dibble band were grooving.

# Вставляем строку

/evening/i\

They played some great tunes.

# Изменяем последнюю строку

$c\

Nurse Neave was too tipsy to help.

# Добавляем строку после строки номер 3

3a\

^C

$ ~ chmod 744 mix.sed

$ ~

Вот что получится в результате выполнения этого сценария:

$ ~ cat quote.txt

The honeysuckle band played all night long for only $90.

It was an evening of splendid music and company.

Too bad the disco floor fell through at 23:10.

The local nurse Miss P. Neave was in attendance.

$ ~ ./mix.sed quote.txt

The Dibble band were grooving.

They played some great tunes.

It was an evening of splendid music and company.

Too bad the disco floor fell through at 23:10.


Nurse Neave was too tipsy to help.

$ ~

Замена подстроки (команда s)

Команда s (substitute) осуществляет во всех адресуемых строках замену подстроки, соответствующей заданному шаблону, указанной подстрокой. Формат команды таков:

 [адрес1[, адрес2]] s/шаблои_поиска/шаблбон_замены/[флаги]

Ниже перечислены возможные флаги. В следующем примере осуществляется замена слова "night" словом "NIGHT":

$ ~ sed -n 's/night/NIGHT/p' quote.txt

The honeysuckle band played all NIGHT long for only $90.

$ ~

Если требуется удалить из строки символ '$', оставьте шаблон замены пустым (не забывайте, что в редакторе sed знак доллара является метасимволом, поэтому он должен быть защищен обратным слешем.

$ ~ sed -n 's/\$//p' quote.txt

The honeysuckle band played all night long for only 90.

$ ~

Флаг g (global) позволяет выполнить глобальную подстановку шаблона замены на место шаблона поиска в пределах каждой адресуемой строки. Предположим, например, что мы хотим заменить все точки в файле quote.txt восклицательными знаками. Следующая команда выполнит работу не полностью:

$ ~ sed 's/\./!/' quote.txt

The honeysuckle band played all night long for only $90!

It was an evening of splendid music and company!

Too bad the disco floor fell through at 23:10!

The local nurse Miss P! Neave was in attendance.

$ ~

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

$ ~ sed 's/\./!/g' quote.txt

The honeysuckle band played all night long for only $90!

It was an evening of splendid music and company!

Too bad the disco floor fell through at 23:10!

The local nurse Miss P! Neave was in attendance!

$ ~

С помощью флага w (write) можно указать файл, в который будут записаны все модифицируемые строки. В показанном ниже примере осуществляется замена слова "splendid" словом "SPLENDID", а все строки, где была выполнена эта замена, помещаются в файл sed.out.

$ ~ sed -n 's/splendid/SPLENDID/w sed.out' quote.txt

$ ~ cat sed.out

It was an evening of SPLENDID music and company.

$ ~

Ссылка на искомую подстроку с помощью метасимвола &

Метасимвол & позволяет сослаться в шаблоне замены на подстроку, соответствующую шаблону поиска. Например, в следующей команде слово "Miss" либо "miss" заменяется фразой "lovely Miss Joan" или "lovely miss Joan" соответственно:

$ ~ sed -n 's/[Mm]iss/lovely & Joan/p' quote.txt

The local nurse lovely Miss Joan P. Neave was in attendance.

$ ~

Заметьте, что пробелы также являются частью шаблона замены.

Чтение строк из файла (команда r)

В процессе обработки входного файла редактор sed позволяет читать текст из другого файла и добавлять его к текущему содержимому буфера, размещая после каждой строки, соответствующей шаблону адреса. Формат предназначенной для этого команды r (read) таков:

 [адрес] r имя_файла

Давайте создадим небольшой файл с именем sedex.txt.

$ ~ cat > sedex.txt

Boom boom went the music.

^C

$ ~

В следующем примере содержимое этого файла выводится на экран после строки файла quote.txt, содержащей слово "company":

$ ~ sed '/company/r sedex.txt' quote.txt

The honeysuckle band played all night long for only $90.

It was an evening of splendid music and company.

Boom boom went the music.

Too bad the disco floor fell through at 23:10.

The local nurse Miss P. Neave was in attendance.

$ ~

Вывод строк в файл (команда w)

Подобно тому как оператор > применяется для перенаправления результатов работы программы в файл, команда w (write) редактора sed позволяет записать в указанный файл строки, отобранные по заданному шаблону адреса. Формат этой команды таков:

[адрес1[, адрес2]] w имя_файла

Если файл не существует, он будет создан, если существует — его содержимое будет перезаписано. Если в сценарии встречается несколько команд w, направляющих результаты в один и тот же файл, данные всех команд, кроме первой, будут добавляться в конец файла. Рассмотрим пример:

$ ~  sed '1,2w sed.out' quote.txt

The honeysuckle band played all night long for only $90.

It was an evening of splendid music and company.

Too bad the disco floor fell through at 23:10.

The local nurse Miss P. Neave was in attendance.

$ ~ cat sed.out

The honeysuckle band played all night long for only $90.

It was an evening of splendid music and company.

$ ~

Здесь содержимое файла quote.txt выводится на экран, а строки с номерами 1 и 2 отправляются в файл с именем sed.out. 

В следующем примере осуществляется поиск строки, содержащей слово "Neave", и если такая строка найдена, она записывается в файл sed.out.

$ ~ sed -n '/Neave/w sed.out' quote.txt

$ ~ cat sed.out

The local nurse Miss P. Neave was in attendance.

$ ~

Досрочное завершение работы (команда q)

Иногда требуется завершить работу редактора sed сразу же после нахождения первого совпадения с шаблоном. Эту задачу решает команда q (quit), имеющая следующий формат: [адрес] q

Обратимся к примеру. Допустим, требуется осуществить поиск строки, содержащей такой шаблон: /\<.a.\{0,2\}\>/

Этому шаблону соответствует любое слово (выражение \< обозначает начало слова, а выражение \>  его конец), в котором вторым символом является буква 'a', а за ней идет не более двух символов. 

В файле quote.txt таких слов четыре:

строка 1 — band,

строка 2 — was,

строка 3 — bad,

строка 4 — was.

Показанная ниже команда находит строку, в которой шаблон встречается первый раз, после чего завершает работу:

$ ~ sed '/\<.a.\{0,2\}\>/q' quote.txt

The honeysuckle band played all night long for only $90.

$ ~

Отображение управляющих символов (команда l)

Иногда даже в текстовых файлах содержатся различного рода непечатаемые символы. Это может быть следствием неправильного ввода данных в текстовом редакторе или ошибок конвертации при загрузке файлов из других систем. При выводе таких файлов. на экране могут быть получены странные результаты, когда вместо непечатаемого символа отображается один или несколько обычных символов непонятного происхождения. Разобраться в таких ситуациях помогает команда  cat -v, которая помечает начало замещающей последовательности символом '^' (знак крышки). Предположим, вы обнаружили незнакомый файл func.txt и хотите узнать его содержимое:

$ ~ cat func.txt

This is the F1 key:Маркер в таблицах

This is the F2 key:Символ якоря

$ ~ cat -v func.txt

This is the F1 key:M-PM-^\M-PM-0M-QM-^

This is the F2 key:M-PM-!M-PM-8M-PM-<M

$ ~

Аналогичным образом будет вести себя и редактор sed при работе с данным; файлом. Если вы попытаетесь просмотреть его содержимое, будет выдано следующее:

$ ~ sed -n '1,$p' func.txt

This is the F1 key:Маркер в таблицах

This is the F2 key:Символ якоря

$ ~

В редакторе существует команда l (list}, аналог рассмотренной выше команды cat -v. 

Формат команды l таков: [адрес1[,адрес2]] l

Ее действие равносильно применению команды p, но при этом все непечатаемые символы заменяются восьмеричными ASCII–кодами (кроме того, длинные строки, выходящие за пределы экрана, разбиваются на части, а конец каждой строки помечается символом '$'). Вот что получится, если применить эту команду к файлу func.txt.

$ ~ sed -n '1,$l' func.txt

This is the F1 key:\320\234\320\260\321\200\320\272\320\265\321\200 \

\320\262 \321\202\320\260\320\261\320\273\320\270\321\206\320\260\321\

\205 $

This is the F2 key:\320\241\320\270\320\274\320\262\320\276\320\273 \

\321\217\320\272\320\276\321\200\321\217\t$

$ ~

Обработка управляющих символов

Одной из задач, для которых редактор sed используется весьма часто, является удаление управляющих, непечатаемых и просто посторонних символов из файлов, которые были загружены из других систем. Ниже приведен фрагмент подобного файла dos.txt.

$ cat -v dos.txt

12332##DISO##45.12^M C0332##LPSO##23.11^M 

01299##USPD##34.46^M

Вот что необходимо сделать:

Примечание: В ряде систем, в которых мне приходилось выполнять подобные преобразования, в конце строки стоит символ перевода строки LF (ASCII–код 10, отображается как ^@). Подобная проблема нередко возникает при передаче файлов между двумя системами, в одной из которых символ новой строки (\n) заменяется последовательностью CR/LF, a в другой — только одним из этих двух управляющих символов.

Задача 1. Удаление всех символов решетки реализуется без особого труда. Для этого достаточно выполнить команду замены s с флагом глобальной подстановки д, указав при этом, что один или более символов '#', идущих подряд, должны быть заменены пробелом:

$ sed 's/##*/ /g' dos.txt | cat -v

12332 DISO 45.12^М 

00332 LPSO 23.11^М 

01299 USPD 34.4б^M

Задача 2. Для удаления всех ведущих нулей следует в команде s оставить шаблону замены пустым, а шаблон поиска задать таким: /^0*/. Он означает, что требуется найти любое количество нулей, стоящих в начале строки.

$ sed 's/^0*//' dos.txt | cat -v

12332##DISO##45.12^M 

332##LPSO##23.11^M 

1299##USPD ##34.46^M

Задача 3. Чтобы избавиться от управляющих символов ^M в конце строк, необходимо. также применить команду s, оставив шаблон замены пустым. А вот при формировании шаблона поиска следует учесть, что мы имеем дело с непечатаемым символом. Нельзя просто ввести символы '^' и 'M', так как полученный шаблон будет означать, что мы ищем букву 'М', стоящую в начале строки. Чтобы действительно создать нужный нам непечатаемый символ, необходимо нажать [Ctrl+V], а затем — клавишу [Enter]. Результат будет выглядеть как регулярное выражение ^M, но на самом деле это экранное представление символа CR.

$ sed 's/^M//' dos.txt | cat -v

12332##DIS0##45.12 

00332##LPSO##23.11 

01299##U5PD#t34.46

Теперь можно попробовать объединить три команды в одну с помощью опции -e;

$ sed -e 's/^0*' -e 's/^M' -e 's/##*/ /g' dos.txt | cat -v

12332 DISO 45.12

332 LPSO 23.11 

1299 USPD 34.46

Выходные данные редактора sed передаются по каналу команде cat -v, которая позволяет убедиться, что вся работа, включая удаление непечатаемых символов, выполнена правильно.

Приведенные выше команды удобнее поместить в файл сценария. Назовем его dos.sed. Вот его текст:

$ cat dos.sed

#! /bin/sed -f

#Имя: dos.sed

#Командная строка: dos.sed dos.txt

#Избавляемся от символа решетки

s/##*/ /g

#Удаляем ведущие нули 

s/^0*//

#Удаляем символы возврата каретки 

s/^M//

На входе данного сценария следует указать файл dos.txt. Сценарий "исправит" этот файл и выведет результат на экран. Если же ввести следующую командную строку:

$ dos.sed dos.txt | tee dos.txt

то результат будет записан обратно в файл dos.txt.

Обработка отчетов

Я часто сталкиваюсь с необходимостью форматировать данные, возвращаемые инструкциями SQL. Для этого приходится писать комплексные сценарии, в которых сразу несколько текстовых фильтров выполняют работу совместно. Рассмотрим результаты выполнения некоторой инструкции SQL, выполняющей обращение к одной из таблиц базы данных:

Database        Size (MB)       Date created

-----------------------------------------------------

GOSOUTH         2244                12/11/97

TRISUD          5632                 8/9/99

(2 rows affected)

Из этой информации нас, предположим, интересуют только имена баз данных, находящиеся в первой колонке. Чтобы их извлечь, необходимо выполнить следующую последовательность действий:

$ sed 's/--*//g' -e '/^$/d' -e '$d' -e '1d' sql.txt | awk '{print $1}'

GOSOUTH

TRISUD

Добавление текста 

 В процессе потоковой обработки файла мне иногда требуется добавить к каждой проверенной строке какой‑нибудь текст, сообщающий о том, как прошла обработка. Предположим, имеется такой файл:

$ ~ cat > ok.txt

АС456

АС492169

АС9967

АС88345

^C

$ ~ sed 's/$/ Passed/' ok.txt

АС456  Passed

АС492169  Passed

АС9967  Passed

АС88345 Passed

$ ~

Наша задача состояла в добавлении слова "Passed" (обработано) в конец каждой строки. Решить ее несложно. Достаточно в шаблоне поиска указать метасимвол '$', означающий конец строки, а в шаблоне замены — пробел и искомое слово: Passed

Вставить новую строку


$ sed '3 a new line content' testfile 

вставит строку после указанного номера здесь 3

$ sed '$ a new line content' testfile  

добавит в конец, символ $

$ sed '/PATTERN/ a new line content' testfile  

вставит после некого содержания (патерна)


И все это хорошо, только выходной файл останется не измененным и это удобно если мы работаем только с stdin, чтобы изменения остались в файле надо воспользоваться опцией -i

Удаление начальной косой черты в путевом имени

Ниже показано, как с помощью редактора sed можно быстро удалить начальный слеш из имени текущего каталога:

$ ~  cd /usr/local

$ echo $PWD | sed 's/^\///g'

usr/local 

$ local

Имя текущего каталога хранится в переменной среды $PWD. Эта переменная обновляется всякий раз, когда выполняется команда cd. Команда echo передает значение переменной по каналу редактору sed, который выполняет несложную обработку: находит в начале строки (метасимвол '^'( символ косой черты (защищен от интерпретации обратной косой чертой) и заменяет его пустой подстрокой.

Объединение команд

Ясо дело можно пользоваться каналом:

$ sed '.........' | sed '...........' 

...,но это не эстетично, для этого существует опция -e которую надо вставить перед каждой командой ("патерном"):

$ sed  -e '.........'  -e '...........'

..., ну и кроме того точка с запятой конечно:

$ sed  '.........; ...........'

....,при использовании опции –e возникает необходимость разрывать одиночные кавычки, а при использовании точки с запятой все команды можно перечислить в одних кавычках.

$ { speedtest-cli | egrep 'Download:|Upload:'; date; iw dev | grep ssid; } | sed -e 's/ssid/SSID:/g' -e '$ a === end of report ===' | tee -a speedtest

https://sites.google.com/site/kfgnb0101

PS: В данном случае использование флага -i не нужно поскольку используется "чудесная" утилита tee, которая перенаправит stdin в указанный файл....вообще наверное следует избегать всякого рода "терминантов" в середине выражения, а ставить их в конец и работать сначала с потоками (что вполне естественно). 

Разбить строку на абзацы


$ ~ echo "sdf2sfd2sd2" | sed -e 's/2/\n/g'

sdf

sfd

sd

$ ~ echo "hjkhjk'huhjkhjk'hjkhjkhjk'jkljkl" | sed "s/'/\n/g"

hjkhjk

huhjkhjk

hjkhjkhjk

jkljkl

$ ~ echo "hjkhjk'huhjkhjk'hjkhjkhjk'jkljkl" | tr "\'" "\n"

hjkhjk

huhjkhjk

hjkhjkhjk

jkljkl

$ ~

$ ~ echo "abcdefgjijklmnop" | sed 's/.\{3\}/&\n/g'

abc

def

gji

jkl

mno

p

$ ~

Примеры операций в sed


8d     ------------------------  Удалить 8-ю строку.

/^$/d   ----------------------Удалить все пустые строки.

1,/^$/d   --------------------Удалить все строки до первой пустой строки, включительно.

/Jones/p   ------------------Вывести строки, содержащие "Jones" (с ключом -n).

s/Windows/Linux/   ----В каждой строке, заменить первое встретившееся слово "Win" на слово "Lin".

s/BSOD/stability/g    ----В каждой строке, заменить все встретившиеся слова "BSOD" на "stability".

s/ *$//   ----------------------Удалить все пробелы в конце каждой строки.

s/00*/0/g   -----------------Заменить все последовательности ведущих нулей одним символом "0".

/GUI/d   --------------------Удалить все строки, содержащие "GUI".

s/GUI//g   --------------Удалить все найденные "GUI", оставляя остальную часть строки без изменений.

http://ant0.ru/sed1line.html

http://emulek.github.io/sed/

http://citforum.ru/operating_systems/articles/tut_6.shtml

http://ant0.ru/sed1line.html                           <<------- SED on line Eric Pement (RU)

http://www.pement.org/sed/sed1line.txt       <<------- SED on line Eric Pement

http://www.pement.org/awk/awk1line.txt      <<------- AWK on line Eric Pement

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

Мы коснулись лишь основ работы с sed, но и полученных знаний достаточно, чтобы с помощью sed решать многие задачи, возникающие в процессе обработки текста.

Утилита tr во многом дополнит фильтрацию и разбор "входного потока" и во многих случаях заменит использование sed.