Как awk заменяет 10 команд Bash

b6c3863e8a12a39fb8e9a0031f7183f1.jpg

Привет, Хабр! Когда я только начинал работать с Linux, каждую задачу обрабатывал через кучку пайпов. Потом мой коллега сказал мне: «Завязывай с этим, попробуй awk». Ну, я попробовал. И это действительно удобно. Сегодня я расскажу, как awk может заменить несколько привычных команд bash.

Выборка столбцов

Классика жанра: есть CSV‑файл, и надо взять второй и четвертый столбцы. Обычно вы бы написали:

cut -d',' -f2,4 file.csv

Но! Зачем cut, если есть awk? Выглядит намного красивее:

awk -F',' '{if (NF >= 4) print $2, $4}' file.csv

Никаких точек с запятыми, странных пайпов. Все в одну строчку. Выглядит приятно.

Фильтрация строк по ключевому слову

Вы смотрите логи. Сервер падает (как обычно), и вы ищете строки с »Error». Обычно это grep:

grep "Error" logs.txt

С awk это выглядит так:

awk '/Error/' logs.txt

awk — это почти как SQL для текстовых файлов. Можно использовать любой шаблон

awk '/^Error [0-9]{3}:/' logs.txt

Вот вам и фильтрация ошибок по HTTP-коду.

Подсчёт строк с условием

«Сколько раз я был прав?» — спросите вы после пары ошибок. С grep -c это просто:

grep -c "Success" logs.txt

А теперь смотрим, как это делает awk:

awk '/Success/ {count++} END {print count}' logs.txt

Здесь важно слово END. Оно активируется после обработки всех строк.

Замена текста

Допустим, вам нужно заменить »проблема» на »задача» в файле. С sed это так:

sed 's/проблема/задача/g' file.txt

А вот и awk, который делает то же самое:

awk '{gsub(/проблема/, "задача"); print}' file.txt

Кстати, это прекрасно работает с JSON.

Уникальные строки

Ну кто из нас не сортировал строки через sort | uniq? Пример:

sort file.txt | uniq

С awk можно проще:

awk '!seen[$0]++' file.txt

seen — это массив. Если строка ещё не встречалась, мы её выводим.

Подсчёт слов

Надо быстро посчитать, сколько слов в файле? Берем wc -w:

wc -w file.txt

Но мы тут за awk, так что:

awk '{count += NF} END {print count}' file.txt

NF — количество полей (читай: слов) в строке. Кажется, что избыточно? Возможно. Но если вы захотите условие «только строки, где слов больше 5», это уже выглядит удобней.

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

Нужно вывести строки с 10 по 20? Старый добрый sed:

sed -n '10,20p' file.txt

С awk всё просто:

awk 'NR>=10 && NR<=20' file.txt

NR — это текущий номер строки.

Вычисление среднего

А вот это совсем интересно. Есть файл с числами в первом столбце, и вы хотите их среднее. Обычно такой Bash:

awk '{sum += $1} END {print sum/NR}' numbers.txt

А теперь сделаем это с проверкой на случай, если файл пустой:

awk '{sum += $1; count++} END {if (count > 0) print sum/count; else print "Нет данных"}' numbers.txt

Конечно, awk — инструмент хороший, но и у него есть свои недостатки.

Обратная сторона awk

  1. Производительность на больших данных. Для обработки очень больших файлов awk может быть менее эффективен, чем инструменты вроде sed, grep или того же Python. Иногда проще написать скрипт на Python с pandas, чем шаманить с awk на терабайтном логе.

  2. Сложность отладки. Если awk-скрипт становится длинным и запутанным, отладка превращается в головную боль. Нет ни встроенного дебаггера, ни удобных средств для профилирования.

  3. Ограниченная поддержка. Несмотря на всю свою мощь, awk не поддерживает сложные структуры данных или современные подходы к программированию (ну, потому что это всё-таки инструмент 70-х годов). Иногда проще подключить полноценный язык программирования.

  4. Зависимость от реализации. Существуют разные версии awk (например, gawk, mawk, nawk), и некоторые возможности могут отличаться между ними. Если ваш скрипт запускается на одном сервере, это не значит, что он так же будет работать на другом.

Такие дела. А какой у вас опыт работы с awk? Делитесь в комментариях.

Приглашаю вас на бесплатные вебинары курса Administrator Linux. Professional:

© Habrahabr.ru