假设你有一个包含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机器,没有我使用过的大多数工具。我认为这是一个有趣的问题。
所以,请不要责怪这个问题,如果你不喜欢它,就忽略它。:-)
这并没有回答原始问题的计数元素,但这个问题是搜索引擎在搜索我想要实现的东西时的第一个结果,所以我认为这可能会帮助一些人,因为它与“分组”功能有关。
我想根据它们的分组来排序文件,其中文件名中存在的一些字符串决定了组。
它使用临时分组/排序前缀,在排序后删除;Sed替换表达式(s#pattern#replacement#g)匹配目标字符串,并在目标字符串所需排序顺序对应的行前加上一个整数。然后,使用cut去除分组前缀。
注意,sed表达式可以被连接(例如,sed -e '<expr>;< expr >;<expr>;')但这里为了可读性将它们分开。
它不漂亮,可能也不快(我处理的项目少于50项),但它至少在概念上简单,不需要学习awk。
#!/usr/bin/env bash
for line in $(find /etc \
| sed -E -e "s#^(.*${target_string_A}.*)#${target_string_A_sort_index}:\1#;" \
| sed -E -e "s#^(.*${target_string_B}.*)#${target_string_B_sort_index}:\1#;" \
| sed -E -e "s#^/(.*)#00:/\1#;" \
| sort \
| cut -c4-
)
do
echo "${line}"
done
例如输入
/this/is/a/test/a
/this/is/a/test/b
/this/is/a/test/c
/this/is/a/special/test/d
/this/is/a/another/test/e
#!/usr/bin/env bash
for line in $(find /etc \
| sed -E -e "s#^(.*special.*)#10:\1#;" \
| sed -E -e "s#^(.*another.*)#05:\1#;" \
| sed -E -e "s#^/(.*)#00:/\1#;" \
| sort \
| cut -c4-
)
do
echo "${line}"
done
/this/is/a/test/a
/this/is/a/test/b
/this/is/a/test/c
/this/is/a/another/test/e
/this/is/a/special/test/d
我知道你在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的列表作为键,它们出现的次数作为值。