Выравнивание результатов воронки вместе с входными данными (здесь результаты ip и whois grep)

Мне нужно выполнить поиск whois в файле, содержащем IP-адреса, и вывести код страны и IP-адрес в новый файл. В моей команде до сих пор я нахожу IP-адреса и получаю уникальную копию, которая не соответствует разрешенным диапазонам. Затем я запускаю поиск whois, чтобы узнать, кто такие иностранные адреса. Наконец, он вытаскивает код страны. Это прекрасно работает, но я не могу заставить его показать мне IP-адрес вместе с кодом страны, поскольку он не включен в вывод whois.

Как лучше всего включить IP-адрес в вывод?

awk '{match($0,/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/); ip = substr($0,RSTART,RLENGTH); print ip}' myInputFile \
  | sort \
  | uniq \
  | grep -v '66.33\|66.128\|75.102\|216.106\|66.6' \
  | awk -F: '{ print "whois " $1 }' \
  | bash \
  | grep 'country:' \
  >> myOutputFile

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

Вот пример ввода:

27 декабря 04:03:30 smtpfive sendmail[14851]: tBRA3HAx014842: to=, delay=00:00:12, xdelay=00:00:01, mailer=esmtp, pri=1681345, relay=redcondor.itctel.com . [75.102.160.236], dsn=4.3.0, stat=Deferred: 451 Превышен лимит получателей для этого отправителя 27 декабря 04:03:30 smtpfive sendmail[14851]: tBRA3HAx014842: to=, delay=00:00:12, xdelay=00:00:01, mailer=esmtp, pri=1681345, relay=redcondor.itctel.com. [75.102.160.236], dsn=4.3.0, stat=Deferred: 451 Превышен лимит получателей для этого отправителя

Спасибо.


person user3788019    schedule 29.12.2015    source источник
comment
awk | sort | uniq | grep | awk | bash | grep звучит немного избыточно. Может быть, вы можете предоставить образец myInputFile вместе с желаемым результатом, чтобы мы могли предложить лучший подход.   -  person fedorqui 'SO stop harming'    schedule 29.12.2015
comment
К вашему сведению, более эффективно ставить >whatever после done, чем открывать файл каждый раз, когда вы хотите запустить команду whois.   -  person Charles Duffy    schedule 29.12.2015
comment
Кроме того, я полностью согласен с @fedorqui - я не могу придумать обстоятельства, при которых ваш конвейер нельзя было бы сократить ровно до двух элементов и не более. (Имейте в виду, что awk может выполнять сортировку, uniq'ing и grepping - инвертировать или иначе)   -  person Charles Duffy    schedule 29.12.2015
comment
Входной файл представляет собой почтовый журнал sendmail. Я не могу нигде прикрепить файл, но добавил пару строк ниже.   -  person user3788019    schedule 29.12.2015
comment
Кроме того, генерация команд для bash с помощью awk в целом подвержена ошибкам безопасности, поскольку awk не имеет никаких средств, эквивалентных printf %q в bash, для безопасного цитирования содержимого оболочки. Этот конкретный случай может быть безопасным, поскольку предоставляемый пользователем контент ограничен соответствием IP-адресам, но это плохая привычка.   -  person Charles Duffy    schedule 29.12.2015
comment
Кроме того, какая у вас версия bash?   -  person Charles Duffy    schedule 29.12.2015
comment
Баш версии 4.1.2(1)   -  person user3788019    schedule 29.12.2015
comment
Итак... вы задали вопрос и через 10 минут приняли первый полученный ответ. Вы даже не МАЛЕНЬКИЙ, но вам любопытно, есть ли какие-либо другие предложения по альтернативным способам решения проблемы, чтобы вы могли рассмотреть плюсы и минусы различных подходов? О, удачи!   -  person Ed Morton    schedule 29.12.2015
comment
@EdMorton, я бы, конечно, проголосовал за хороший ответ, если бы вы сочли нужным его предоставить.   -  person Charles Duffy    schedule 30.12.2015
comment
@CharlesDuffy Обычно я даже не читаю вопросы, на которые уже выбран ответ, поскольку ОП, по-видимому, получил то, что хотел, и пошел дальше, поэтому предоставление возможного решения было бы пустой тратой времени. Много вопросов без ответов, чтобы тратить время на чтение :-).   -  person Ed Morton    schedule 30.12.2015
comment
@EdMorton, конечно, но аудитория вопроса - это больше, чем просто ОП - это любой, у кого есть похожая проблема, если предположить, что она достаточно хорошо задана, чтобы быть общей. И если это не так, это повод для редактирования или закрытия вопроса. :)   -  person Charles Duffy    schedule 30.12.2015
comment
Да, но если на вопрос нет ответа, вы можете быть уверены, что ваши усилия полезны по крайней мере для одного человека, а если на него уже есть ответ, рентабельность инвестиций уменьшается :-).   -  person Ed Morton    schedule 31.12.2015


Ответы (1)


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


Ниже будет работать с bash 4.0 или новее (требуются ассоциативные массивы):

#!/bin/bash
#      ^^^^- must not be /bin/sh, since this uses bash-only features

# read things that look vaguely like IP addresses into associative array keys
declare -A addrs=( )
while IFS= read -r ip; do
  case $ip in 66.33.*|66.128.*|75.102.*|216.106.*|66.6.*) continue;; esac
  addrs[$ip]=1
done < <(grep -E -o '[0-9]+[.][0-9]+[.][0-9]+[.][0-9]+')

# getting country code from whois for each, printing after the ip itself
for ip in "${!addrs[@]}"; do
  country_line=$(whois "$ip" | grep -i 'country:')
  printf '%s\n' "$ip $country_line"
done

Альтернативная версия, которая будет работать со старыми (3.x) выпусками bash, используя sort -u для генерации уникальных значений, а не внутри оболочки:

while read -r ip; do
  case $ip in 66.33.*|66.128.*|75.102.*|216.106.*|66.6.*) continue;; esac
  printf '%s\n' "$ip $(whois "$ip" | grep -i 'country:')"
done < <(grep -E -o '[0-9]+[.][0-9]+[.][0-9]+[.][0-9]+' | sort -u)

Более эффективно выполнять перенаправление ввода и вывода для сценария в целом, чем помещать перенаправление >> после самого printf (которое будет открывать файл перед каждой операцией печати и снова закрывать его после, вызывая существенное снижение производительности), поэтому предлагаемый вызов для этого скрипта выглядит примерно так:

countries_for_addresses </path/to/logfile >/path/to/output
person Charles Duffy    schedule 29.12.2015
comment
Это сработало хорошо. Теперь мне просто нужно добавить бит для grep -v '66.33\|66.128\|75.102\|216.106\|66.6' и все готово. - person user3788019; 29.12.2015
comment
Можно также реализовать эту логику в bash. case $ip in 66.33.*|66.128.*|75.102.*|216.106.*|66.6.*) continue;; esac - person Charles Duffy; 29.12.2015
comment
@ user3788019, ... мое предложение выше на самом деле содержит меньше ошибок, поскольку оно соответствует этим строкам только в позиции префикса, а не исключает также 1.2.66.6 или 1.66.6.2, хотя вы также можете переписать свой grep: grep -E -v '^(66[.]33|66[.]128|75[.]102|216[.]106|66[.]6)'. - person Charles Duffy; 29.12.2015
comment
@user3788019 user3788019, ... кстати, если вам интересно, почему я предпочитаю [.] \., попробуйте посмотреть, что происходит, когда последний помещается внутри обратных кавычек. - person Charles Duffy; 29.12.2015