1

好的,我有将数据输出到文本文件的这一行。唯一的问题是我需要线条是独一无二的。那么,如果它要添加一条已经存在的行,我该如何防止呢?这是我的脚本:

 tcpdump -lvi any "udp port 53" 2>/dev/null|grep -E 'A\?'|awk '{print $(NF-1)}' >> /tmp/domains

我是否通过管道将其 awk 并以某种方式删除重复项?我是否有另一个脚本运行每个分钟来删除重复项?

这是加载 Amazon.com 的输出:

 amazon.com.
 amazon.com.
 www.amazon.com.
 www.amazon.com.
 amazon.com.
 www.amazon.com.
 a0e90b2a1701074fb52d450dc80084cb1.labs.cloudfront.net.
 a0e90b2a1701074fb52d450dc80084cb1.labs.cloudfront.net.
 ad.doubleclick.net.
 ad.doubleclick.net.
 ecx.images-amazon.com.
 ...more

在查看我的输出时,我似乎需要弄清楚为什么会有一个尾随点。

4

6 回答 6

2

您永远不需要 grep 和 awk,因为 awk 可以做任何 grep 可以做的事情,如果您使用 awk,只需使用 awk:

tcpdump -lvi any "udp port 53" 2>/dev/null|
awk '/A\?/{ key=$(NF-1); if (!seen[key]++) print key }' > /tmp/domains

如果您需要停止此脚本并重新启动它,但只将新域附加到输出文件,您只需要先读取输出文件以填充“seen”数组,例如:

tcpdump -lvi any "udp port 53" 2>/dev/null|
awk -v outfile="/tmp/domains" '
    BEGIN{
        while ( (getline key < outfile) > 0 )
            seen[key]++
        close(outfile)
    }
    /A\?/{ key=$(NF-1); if (!seen[key]++) print key >> outfile }
'
于 2013-08-22T13:28:47.767 回答
1

这将只打印出看不见的输入行,而不是像其他一些重复的删除 awk 脚本那样在最后打印出来。

awk '{host=$(NF-1)} !(host in list) {print host; list[host]++}'

如果您只想定期运行整个事情并更新列表,那么执行以下操作可能会更容易

tcpdump and extract hostnames | sort -u /tmp/domains - > /tmp/domains.new
mv /tmp/domains.new /tmp/domains
于 2013-08-22T10:59:56.153 回答
0

改变这个

tcpdump -lvi any "udp port 53" 2>/dev/null|grep -E 'A\?'|awk '{print $(NF-1)}'

至:

tcpdump -lvi any "udp port 53" 2>/dev/null|grep -E 'A\?'|awk '{a[$(NF-1)]++}END{for(i in a)print i}'
于 2013-08-22T07:22:32.527 回答
0

除非您打算长时间运行它或有一个非常繁忙的站点,否则您可以通过将以前的查找保存到 awk 哈希来确保唯一性。这在这里有效:

tcpdump -lvi any "udp port 53" 2> /dev/null | grep -E 'A\?' | awk '!h[$(NF-1)]++ { print $(NF-1) }' > /tmp/domains

否则,您需要将tcpdump/grep输出的块保存到临时文件并将其与/tmp/domains. 我知道的最好方法是保持输出单独排序,然后使用sort -mu. 这在这里有效:

lim=10000
tmpfile=$(mktemp /tmp/unique.domain.XXXXXX)
unique_domains=/tmp/domains

tcpdump -lvi any "udp port 53" 2> /dev/null | grep -E 'A\?' | while read line; do
  awk -v lim=$lim '!h[$(NF-1)]++ { print $(NF-1); ndomain++ }; ndomain > lim { exit }' | sort > $tmpfile
  sort -mu $tmpfile $unique_domains 2> /dev/null > $unique_domains.tmp
  mv $unique_domains.tmp $unique_domains
done

如果您想在/tmp/domain运行时访问,您需要添加一些文件锁定,例如lockfile

lim=10000
lock=/tmp/domains.lock
tmpfile=$(mktemp /tmp/unique.domain.XXXXXX)
unique_domains=/tmp/domains

tcpdump -lvi any "udp port 53" 2> /dev/null | grep -E 'A\?' | while read line; do 
  awk -v lim=$lim '!h[$(NF-1)]++ { print $(NF-1); ndomain++ }; ndomain > lim { exit }' | sort > $tmpfile
  lockfile $lock
  sort -mu $tmpfile $unique_domains 2> /dev/null > $unique_domains.tmp
  mv $unique_domains.tmp $unique_domains
  rm $lock
done

现在要获取您的快照,/tmp/domains请执行以下操作:

lockfile /tmp/domains.lock
cp /tmp/domains unique_domains
sync
rm -f /tmp/domains.lock
于 2013-08-22T07:39:51.857 回答
0

回答:

这是一个使用管道连接到 bash 函数的解决方案

checkDuplicates() {
    touch -- "$1" # Where $1 is a file that holds the data. It could be the same file that you write to or any other one.
    while read -r nextCheck; do
        grep -q -m 1 "$nextCheck" "$1" || printf "%s\n" "$nextCheck"
    done
}

myFile='/tmp/domains'
YOURANYCOMMAND | checkDuplicates "$myFile" > "$myFile"

奖励技巧:

当您想查看两个文件之间的差异时,这可能很有用。例如: fileA:

what
is
this

fileB:

what
I
is
dont
this
even

然后这段代码

cat 'fileB' | checkDuplicates 'fileA'

即将输出

I
Dont
Even
于 2013-08-22T21:56:19.303 回答
0

嗯,你需要一个域列表(唯一的)吗?还是你需要整条线?

您可以尝试使用整行作为 awk 数组中的键,但时间戳会有所不同,并且数据包大小等。

gawk 'BEGIN{count=0} {arr[$0]=$(NF-1); if (length(arr) > count) { count++; print $0 )}'domain

虽然可能对您更有用的是每个域的行...

gawk '{ domain = $(NF-1); arr[ domain ] = $0 ;}  
    END {  for (entry in arr) print "domain:",entry, arr[entry]} '

一些输出会很有用。好的,我现在看到了输出,

域名必须以点结尾祝你好运!!

附言。用这个

cmd | gawk 'BEGIN{ count = 0 } { 
             arr[ $0 ] = $(NF-1); 
             if (length(arr) > count) { 
                 count++; 
                 print $0 
             }
      }'  

因为它不断向输出中添加新域。最好不要查找域并使用 ips 代替...

replace $(NF-1) with |& host -t A domain  or so

请参阅高级功能 :: gawk 信息页面“info gawk”中的双向管道

为了使它有用,您需要将新域插入到排序列表中。虽然我不建议为此使用 ncurses,但将输出传送到一个在单个排序表中显示数据的 java 程序不会太难......

于 2013-08-22T07:33:20.353 回答