假设你有一个包含IP地址的文件,每行一个地址:
10.0.10.1
10.0.10.1
10.0.10.3
10.0.10.2
10.0.10.1
您需要一个shell脚本来计算每个IP地址在文件中出现的次数。对于前面的输入,您需要以下输出:
10.0.10.1 3
10.0.10.2 1
10.0.10.3 1
一种方法是:
cat ip_addresses |uniq |while read ip
do
echo -n $ip" "
grep -c $ip ip_addresses
done
然而,它真的是远远不是有效的。
如何使用bash更有效地解决这个问题?
(有一件事要补充:我知道它可以从perl或awk解决,我对bash中更好的解决方案感兴趣,而不是在那些语言中。)
额外的信息:
假设源文件是5GB,运行算法的机器有4GB。所以排序不是一个有效的解决方案,多次读取文件也不是。
我喜欢类似散列表的解决方案-任何人都可以提供改进的解决方案?
附加信息#2:
有些人问我为什么要在bash中做,而在例如perl中更容易。原因是,在机器上,我必须这样做perl是不可为我。这是一台定制的linux机器,没有我使用过的大多数工具。我认为这是一个有趣的问题。
所以,请不要责怪这个问题,如果你不喜欢它,就忽略它。:-)
awk + sort(带版本排序标志)的组合可能是最快的(如果你的环境有awk的话):
echo "${input...}" |
{m,g}awk '{ __[$+_]++ } END { for(_ in __) { print "",+__[_],_ } }' FS='^$' OFS='\t' |
gsort -t$'\t' -k 3,3 -V
只有后GROUP-BY汇总行被发送到排序实用程序——与毫无理由地对输入行进行预先排序相比,这是一种系统密集型排序。
对于小输入,例如少于1000行左右,只需直接排序|uniq -c它。
3 10.0.10.1
1 10.0.10.2
1 10.0.10.3
我知道你在Bash中寻找一些东西,但如果其他人可能在Python中寻找一些东西,你可能会考虑这样做:
mySet = set()
for line in open("ip_address_file.txt"):
line = line.rstrip()
mySet.add(line)
由于集合中的值在默认情况下是唯一的,而Python在这方面非常擅长,因此您可能会在这里赢得一些东西。我还没有测试代码,所以它可能有漏洞,但这可能会让你明白。如果你想要计数出现的次数,使用字典而不是集合很容易实现。
编辑:
我不擅长阅读,所以我答错了。这里有一个字典片段,可以计算发生的次数。
mydict = {}
for line in open("ip_address_file.txt"):
line = line.rstrip()
if line in mydict:
mydict[line] += 1
else:
mydict[line] = 1
字典mydict现在保存一个唯一IP的列表作为键,它们出现的次数作为值。