Подсчёт и выборка данных при помощи awk и column в терминале, операции с дробными числами в bash

Говорят, что изучение bash «по взрослому» начинается с команды awk. И действительно раньше эти конструкции отталкивали, но как оказалось, всё не так страшно как представлялось вначале пути. И теперь меня уже пугают другие bash конструкции, типа сложных условий sed обработки и выборки. Неужели я перешёл на «взрослый» уровень? Не знаю. А вот команда awk понравилась за свою гибкость, ведь в ней доступны условия и даже подскрипты, позволяющие разобрать данные каждой колонки, проверить и обработать их с нужной логикой. Кстати, если быть точным, это уже никакой не bash, это awk!

Допустим у нас есть некий лог файл, в котором через разделитель мы сохраняем инфу с числами. Разобъём его на клонки командой column указав этот разделитель. Ну вот например, подсчёт количества строк с условием, что значение в колонке 9 больше или равно 3:

Какой grep вам такое выполнит? Нет, силу регулярок, конечно никто не отменял и grep -e справится, но нужно писать регулярку. А если условий будет несколько, придётся писать и под них регулярки. А здесь мы сразу указываем условия напрямую. Ну хорошо, допустим первый пример неудачный, тогда вот такой:

Вот здесь уж точно только awk справится с такими задачами. В первом случае мы просто подсчитали сумму данных в колонке 9. А второй командой при помощи условия в awk мы подсчитали сумму только тех цифр, что более или равны 3.

Кстати, если в колонке были дробные числа типа float, то и результат будет дробным. А вы знали, что bash при всех своих достоинствах, тупо не работает с  дробными числами? При делении они их округляет в меньшую сторону, а при остальных операциях выдаёт ошибку. Попробуем:

И как же быть, когда нам нужно произвести в bash операции с дробными числами? Ответ прост: использовать отдельный скриптовый язык awk передав ему управление потоком:

Вот почему я сразу заметил, что awk вам не bash! А недавно, у меня возникла ситуация, в которой column отказывался форматировать вывод поскольку в нем присутствовала кириллица. Он просто проглатывал поток и ничего не отдавал. Причём в терминале column разбивл без проблем, проблема была с вызовом shell из под php. А вот awk справился с этой задачей, обработав строки и колонки по разделителю:

А вот что он ещё умеет:

Синтаксис командыОписание
Печатает только первый и третий столбцы, используя stdin
Печатает все столбцы, используя stdin
Печатает только элементы второго столбца, соответствующие шаблону «pattern», используя stdin
Как и sed, awk использует ключ -f для получения инструкций из файла, что полезно, когда их большое количество и вводить их вручную в терминале непрактично.
Исполняет program, используя данные из inputfile
Классическое «Hello, world» на awk
Печатает все, что вводится из командной строки, пока не встретится EOF
Скрипт awk для классического «Hello, world!» (сделайте его исполняемым с помощью chmod и запустите)
Комментарии в скриптах awk
Определяет разделитель полей как null, в отличие от пробела по умолчанию
Разделитель полей также может быть регулярным выражением
Печатает длину самой длинной строки
Печатает все строки длиннее 80 символов
Печатает каждую строку, содержащую хотя бы одно поле (NF означает Number of Fields)
Печатает семь случайных чисел в диапазоне от 0 до 100
Печатает общее количество байтов, используемое файлами в текущей директории
Печатает общее количество килобайтов, используемое файлами в текущей директории
Печатает отсортированный список имен пользователей
Печатает количество строк в файле, NR означает Number of Rows
Печатает четные строки файла.
Печатает общее количество байтов файла, который последний раз редактировался в ноябре.
Регулярное выражение для всех записей в первом поле, которые начинаются с большой буквы j.
Регулярное выражение для всех записей в первом поле, которые не начинаются с большой буквы j.
Экранирование двойных кавычек в awk.
Печатает «<A>bcd»
Модифицирует inventory и печатает его с той разницей, что значение второго поля будет уменьшено на 10.
Даже если поле шесть не существует в inventory, вы можете создать его и присвоить значение, затем вывести его.
OFS — это Output Field Separator (разделитель выходных полей) и команда выведет «a::c:d» и «4», так как хотя второе поле аннулировано, оно все еще существует, поэтому может быть подсчитано.
Еще один пример создания поля; как вы можете видеть, поле между $4 (существующее) и $6 (создаваемое) также будет создано (как пустое $5), поэтому вывод будет выглядеть как «a::c:d::new» «6».
Отбрасывание трех полей (последних) путем изменения количества полей.
Это регулярное выражения для установки пробела в качестве разделителя полей.

Печатает только «a».
Печатает только первое совпадение с регулярным выражением.
Устанавливает в качестве разделителя полей \\
Если у нас есть запись вида
«John Doe
1234 Unknown Ave.
Doeville, MA»,
этот скрипт устанавливает в качестве разделителя полей новую строку, так что он легко может работать со строками.
Если файл содержит два поля, записи будут напечатаны в виде:

«field1:field2

field3;field4

…;…»
так как разделитель выходных полей — две новые строки, а разделитель полей — «;».

Будет напечатано 17 и 18 , так как в качестве выходного формата (Output ForMaT) указано округление чисел с плавающей точкой до ближайших целых значений.

Вы можете использовать printf практически так же, как и в C.

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

Простой пример извлечения данных, где второе поле записывается под именем «phone-list».

Записывает имена, содержащиеся в $1, в файл, затем сортируем и выводим результат в другой файл.

Простой поиск для foo или bar.

Простые арифметические операции (в большинстве похожи на C)

Простой расширяемый калькулятор

Печатает каждую запись между start и stop.

Правила BEGIN и END исполняются только один раз, до и после каждой обработки записи.

Простое условие. awk, как и C, также поддерживает операторы ?:.

Печатает первые три поля каждой записи, по одной в строке.

Печатает первые три поля каждой записи, по одной в строке.

Выход с кодом ошибки, отличным от 0, означает, что что-то идет не так. Пример:

Печатает awk file1 file2

Удаляет элементы в массиве

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

awk-вариант функции ctime() в C. Так вы можете определять свои собственные функции в awk.

Генератор случайных чисел Cliff.

Анонимный лог Apache (IP случайные)

Ну и добавлю ещё базовый синтаксис: