Bash: Пример оптимизации команд фильтрации с grep и awk

Bash: Пример оптимизации команд фильтрации с grep и awk

Приветствую!

Расскажу про одну задачку, которую решал на днях🧑‍💻 Вводные данные я немного видоизменил, но суть осталась та же.

Подписывайтесь на наш телеграм @r4ven_me📱, чтобы не пропустить новые публикации на сайте😉. А если есть вопросы или желание пообщаться по тематике — заглядывайте в Вороний чат @r4ven_me_chat🧐.

Имеется два csv файла:

📄ping_status.csv — содержит дигностическую информацию о доступности хостов по пингу.

Пример:

ID|DNS_NAME|IP_ADDRESS|PING_STATUS
1|host1.corp.local|10.66.163.62|success
2|host2.corp.local|10.20.202.136|fail
3|host3.corp.local|10.251.60.85|success
4|host4.corp.local|10.137.229.129|success
5|host5.corp.local|10.161.196.50|success
6|host6.corp.local|10.214.27.115|fail
7|host7.corp.local|10.188.87.205|fail
8|host8.corp.local|10.2.203.4|success
9|host9.corp.local|10.8.74.100|fail
10|host10.corp.local|10.21.116.174|success

📃device_list.csv — список устройств с указанием подразделения и типа.

Пример:

DEPARTMENT;IP_ADDRESS;DEVICE_TYPE
QA;10.92.104.3;workstation
HR;10.25.101.192;server
DevOps;10.242.234.48;workstation
DevOps;10.35.10.218;switch
Legal;10.196.97.105;printer
DevOps;10.105.56.232;router
Support;10.34.3.56;printer
IT;10.40.93.15;router
IT;10.72.223.200;laptop
Legal;10.60.206.98;switch

Задача: необходимо отобрать хосты с неуспешным статусом диагностики (поле PING_STATUS) из файла ping_status.csv и проверить их наличие в файле device_list.csv для подразделения DevOps (поле DEPARTMENT):

Немного поразмыслив составил такой однострочник:

while IFS= read -r line; do [ -n "$line" ] && grep -F -w -- "$line" /tmp/device_list.csv | awk -F ';' '$1 == "DevOps"'; done < <(awk -F '|' '$4 != "success" {print $3}' /tmp/ping_status.csv) | sort -u

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

Команда представляет собой цикл while, который построчно считывает псевдо файл (конструкция <(..)), который является выводом другой команды — awk, которая в свою очередь задает в качестве разделителя |, отбирает устройства, у которых статус доступности не равно success и выводит только 3 столбец — IP адрес из файла ping_status.csv. Затем с помощью grep выполняется поиск совпадений в файле device_list.csv.

Опытный shell-разработчик, в отличие от меня, сразу увидит говнокод. Проблема заключается в том, что grep выполняется для каждой соответствующей условию строки из ping_status.csv в device_list.csv. Ничего страшного, если у вас устройств пару десятков или сотен. Это рабочий способ решить задачу. Но если речь идет о сотнях тысяч (мой случай), то столько раз выполнять grep — роскошь непозволительная. На обработку уйдет очень много времени.

Для примера:
device_list.csv — 300000 строк
ping_status.csv — 1000000 строк

Время отработки команды выше при таких условиях будет: 29 минут, 17 секунд 😵

Не вариант.

Т.к. данную процедуру мне необходимо было проводить не один раз и с разными параметрами, решил оптимизировать команду, в т.ч. с помощью нейронки. В итоге получилось сформировать 2 варианта: с помощью grep и awk:

1) Быстрый вариант с grep (в один проход) + awk:

grep -F -w -f <(awk -F'|' '$4 != "success" && $4 ~ /[^[:space:]]/ {print $3}' /tmp/ping_status.csv) /tmp/device_list.csv | awk -F ';' '$1 == "DevOps"' | sort -u

Команда отработала за: 1.8 секунды🤯

Тут вся суть в использовании ключа -f, который позволяет использовать в качестве входного шаблона указанный файл (в моем случае псевдофайл), обрабатывая его построчно.

Ну а [^[:space:]] — это регулярка, позволяющее исключить пустые строки.

2) Быстрый вариант только с awk:

awk -F'|' '
    FNR==NR && $4 != "success" && $4 ~ /[^[:space:]]/ {ips[$3]; next}
    FNR!=NR && $1 == "DevOps" && $2 in ips {seen[$0]++}
    END {for (line in seen) print line}
    ' /tmp/ping_status.csv FS=';' /tmp/device_list.csv

Команда отработала за: 1.7 секунды🤔

☝️Синтаксис awk для рептилоидов.

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

В общем, результат на лицо😒

Если вдруг у вас есть идеи, как решить задачу более элегантно, то напишите свой вариант в комментариях👍

И берегите своё время👨‍💻 Хорошего дня!

Не забывайте про нашу телегу📱и чат💬
Всех благ✌️

That should be it. If not, check the logs 🙂

Подписаться
Уведомить о
0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии