вывод grep nmap, условно печатать выбранные строки

Я пытаюсь написать сценарий bash, который будет считывать серию IP-адресов в файле .txt и выполнять сканирование nmap на каждом отдельном IP-адресе с помощью NSE (smb-os-discovery) с ним. Из этого вывода я хотел бы напечатать только определенные строки, но только если одна из них соответствует определенному шаблону.

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

#!/bin/bash
for server in $(cat servers-smb.txt); do
nmap --script smb-os-discovery $server | grep "report\|OS: Windows"
done

При запуске приведенного выше скрипта в выводе есть серверы, работающие под управлением Windows, а также строка report для тех, которые не работают, что ожидается, поскольку выражение grep содержит оператор «ИЛИ».

Любая помощь в этом будет высоко оценена.


person dude    schedule 22.01.2015    source источник
comment
Если ваша основная проблема заключается в поиске лучшего выражения grep, опубликуйте пример вывода вашей команды nmap, с которым мы можем работать.   -  person John Zwinck    schedule 22.01.2015


Ответы (1)


grep нелегко приспособиться к тому, что вы хотите, но Awk вполне подходит.

#!/bin/sh
while read server; do
   nmap --script smb-os-discovery "$server" |
    awk '/report/ { r=$0 } /OS: Windows/ { print r; print; exit }'
done <servers-smb.txt

Сценарий Awk собирает строку отчета, а затем печатает ее вместе со строкой OS:, если она соответствует «OS: Windows».

Обратите также внимание на измененный шебанг (в этом скрипте нет ничего специфичного для Bash, поэтому его можно запускать с обычным sh), предпочтение while вместо for + Бесполезный cat, правильное цитирование "$server" внутри цикла и, наконец, использование правильного отступа внутри блока управления для удобочитаемости.

Менее привлекательным подходом было бы наложение двух строк grep. Я упомянул это здесь для полноты картины — все, что содержит более одного grep, вероятно, лучше сделать в виде сценария Awk или sed.

grep "report\|OS: Windows" | grep -B1 "OS: Windows"

Наконец, простой способ добиться того же результата, используя только grep, состоит в том, чтобы ввести IP-адрес в вывод, поскольку он уже есть в переменной server.

while read server; do
    nmap --script smb-os-discovery "$server" |
    # XXX: suboptimal; see below
    grep "OS: Windows" | sed "s/^/$server:/"
done <servers-smb.txt

но, конечно, grep | sed также является антипаттерном, и его лучше выражать просто как сценарий sed:

while read server; do
    nmap --script smb-os-discovery "$server" |
    sed -n "/OS: Windows/s/^/$server:/p"
done <servers-smb.txt

Дополнительным преимуществом этого является сбор вывода для одного хоста в одной строке, что делает его более подходящим для дополнительной обработки с помощью типичных линейно-ориентированных инструментов Unix.

person tripleee    schedule 22.01.2015