Bash 脚本: 计算文件中的唯一行数

情况:

我有一个包含 IP 地址和端口的大文件(数百万行) ,这些 IP 地址和端口来自于几个小时的网络捕获,每行一个 IP/port。行的格式如下:

ip.ad.dre.ss[:port]

预期结果:

我在记录时收到的每个数据包都有一个条目,所以有很多重复的地址。我希望能够通过某种 shell 脚本来运行它,这种脚本能够将其缩减为格式化的行

ip.ad.dre.ss[:port] count

其中 count是特定地址(和端口)出现的次数。不需要做特殊的工作,将不同的端口视为不同的地址。

到目前为止,我正在使用这个命令从日志文件中提取所有的 ip 地址:

grep -o -E [0-9]+\.[0-9]+\.[0-9]+\.[0-9]+(:[0-9]+)? ip_traffic-1.log > ips.txt

由此,我可以使用一个相当简单的正则表达式来清除由我的地址(我不关心这个)发送的所有 ip 地址

然后,我可以使用以下内容来提取独特的条目:

sort -u ips.txt > intermediate.txt

我不知道如何用 sort 聚合行计数。

135442 次浏览

可以使用 uniq命令获取排序后重复行的计数:

sort ips.txt | uniq -c

为了获得最常见的结果(感谢 Peter Jaric) :

sort ips.txt | uniq -c | sort -bgr

对于 计数的唯一行总数(即不考虑重复行) ,我们可以使用 uniq或 Awk 和 wc:

sort ips.txt | uniq | wc -l
awk '!seen[$0]++' ips.txt | wc -l

Awk 的数组是关联的,因此它的运行速度可能比排序快一些。

生成文本文件:

$  for i in {1..100000}; do echo $RANDOM; done > random.txt
$ time sort random.txt | uniq | wc -l
31175


real    0m1.193s
user    0m0.701s
sys     0m0.388s


$ time awk '!seen[$0]++' random.txt | wc -l
31175


real    0m0.675s
user    0m0.108s
sys     0m0.171s

这是获得重复行数的最快方法,并将它们以最少到最多的频率很好地打印出来:

awk '{!seen[$0]++}END{for (i in seen) print seen[i], i}' ips.txt | sort -n

如果你不关心性能,你想要一些更容易记住的东西,那么简单地运行:

sort ips.txt | uniq -c | sort -n

附注:

Sort-n 将字段解析为数字,这是正确的,因为我们使用计数进行排序。