Я думаю, что find вполне подходит для этой
находки. -тип d! -regex '^. *)' -ls
-regex '^.*) 'соответствует всем именам, оканчивающимся скобкой,! инвертирует это, - опция типа d предназначена для каталогов, - ls (необязательно) делает вывод похожим на ls
К сожалению, sed
не может запускать внешние команды, одновременно передавая параметры, взятые из входных данных.
Это решение сценария Bash, которое вам подойдет:
tail -f dnsmasq.log | { while IFS= read -r line ; do { [[ "${line}" =~ ": query[A]" ]] && printf '%s %s\n' "${line% *} " $(dig +short -x "${line##* }"); } || echo "${line}"; done ; }
Разбито для объяснения:(только для ясности, может не работать при копировании и вставке)
tail -f dnsmasq.log | \
{ \
while IFS= read -r line ; do \ # for each line read in from tail...
if [[ "${line}" =~ ": query[A]" ]] ; # if it has the literal string ': query[A]'
then \
printf '%s %s\n' "${line% *} " \ # print it (purged of last field, which is the IP address)...
$(dig +short -x "${line##* }") \ # along with dig's output
else \ # otherwise...
echo "${line}" \ # just print it all as it is
fi \
done ; \
}
Это вроде как работает (, но используется «awk» вместо «sed»):
$ echo $'Apr 1 00:47:43 dnsmasq[1004]: query[A] gs-loc.apple.com from 8.8.8.8' | awk '/query/{ IP=$NF; $NF=""; L=$0; "host " IP | getline name; $0=name; print L,$NF }'
Apr 1 00:47:43 dnsmasq[1004]: query[A] gs-loc.apple.com from google-public-dns-a.google.com.
... нужно немного доработать, например, если поиск хоста не работает; возможно, «запрос» регулярного выражения должен быть немного более конкретным.
Вот объяснение команды awk:
/запрос/{...} выполнить {...} в строках, соответствующих регулярному выражению 'query' (просто напечатать другие)
IP=$NF установить новую переменную 'IP' на значение последнего поля в строке (IP-адрес)
$NF="" удалить последнее поле в строке
L=$0 установить новую переменную 'L' в оставшуюся строку (т.е. без IP-адреса)
"хост" IP | getline name запустите 'host' по IP-адресу и поместите результат в новую переменную 'name'
$0=имя установить текущую строку для вывода команды 'host', чтобы мы могли использовать $NF в следующей команде.
print L,$NF Print 'L' (строка ввода без IP-адреса )и последнее поле команды host (имя хоста ).
Запуск dig
для каждого IP-адреса будет очень неэффективным и добавит нагрузку на ваш DNS-сервер. Я бы использовал perl
здесь:
perl -MSocket -pe 's{(?<![\d.])\d+\.\d+\.\d+\.\d+(?![\d.])}{
$ip = inet_aton($&);
$cache{$ip} //= gethostbyaddr($ip,AF_INET) // "UNKNOWN[$&]"
}ge'
Это запрашивает службу имен вашей системы, поэтому, возможно, /etc/hosts
, DNS, mDNS, LDAP, NIS+... или что-то другое, настроенное для разрешения имен хостов в /etc/nsswitch.conf
или эквивалентное в вашей системе, возможно, через службу имен службы кэширования, такие как nscd
или sssd
, и мы также реализуем наше кэширование, чтобы избежать повторного запроса одного и того же IP-адреса.
Мы сопоставляем только последовательности из 4.
-разделенных десятичных чисел, а не другие форматы адресов IPv4, но обратите внимание, что для inet_aton()
начальные 0 заставляют числа считаться восьмеричными, поэтому 010.010.010.010
на самом деле8.8.8.8
(то же, что и для большинства вещей, которые принимают IP-адреса в качестве аргументов, но неdig -x
).
Если вам нужно запрашивать DNS-сервер только так, как это делает dig
, вы можете использовать Net::DNS
вместоgethostbyaddr()
:
perl -MNet::DNS -pe '
sub resolve {
my ($r) = rr($_[0]);
if (defined($r)) {
return $r->ptrdname;
} else {
return "UNKNOWN[$_[0]]";
}
}
s{(?<![\d.])\d+\.\d+\.\d+\.\d+(?![\d.])}{$cache{$&} //= resolve $&}ge'