假设你有一个包含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机器,没有我使用过的大多数工具。我认为这是一个有趣的问题。

所以,请不要责怪这个问题,如果你不喜欢它,就忽略它。:-)


当前回答

我会这样做:

perl -e 'while (<>) {chop; $h{$_}++;} for $k (keys %h) {print "$k $h{$k}\n";}' ip_addresses

但uniq可能适合你。

其他回答

cat ip_addresses | sort | uniq -c | sort -nr | awk '{print $2 " " $1}'

这个命令将提供您想要的输出

要根据一组现有字段汇总多个字段,请使用下面的示例:(根据您的需求替换$1、$2、$3、$4)

cat file

US|A|1000|2000
US|B|1000|2000
US|C|1000|2000
UK|1|1000|2000
UK|1|1000|2000
UK|1|1000|2000

awk 'BEGIN { FS=OFS=SUBSEP="|"}{arr[$1,$2]+=$3+$4 }END {for (i in arr) print i,arr[i]}' file

US|A|3000
US|B|3000
US|C|3000
UK|1|9000

将数据导入sqlite db并使用sql语法(只是另一个想法)。 我知道这对于这个例子来说太多了,但是对于有多个文件(表)的复杂查询是有用的

#!/bin/bash
trap clear_db EXIT
clear_db(){ rm -f "mydb$$"; }

# add header to input_file (IP)
INPUT_FILE=ips.txt

# import file into db
sqlite3 -csv mydb$$ ".import ${INPUT_FILE} mytable"

# using sql statements on table 'mytable' 
sqlite3 mydb$$ -separator " "  "SELECT IP, COUNT(*) FROM mytable GROUP BY IP;"

10.0.10.1 3
10.0.10.2 1
10.0.10.3 1
sort ip_addresses | uniq -c

这将首先打印计数,但除此之外,它应该完全是您想要的。

大多数其他解决方案计算重复。如果你真的需要分组键值对,试试这个:

以下是我的示例数据:

find . | xargs md5sum
fe4ab8e15432161f452e345ff30c68b0 a.txt
30c68b02161e15435ff52e34f4fe4ab8 b.txt
30c68b02161e15435ff52e34f4fe4ab8 c.txt
fe4ab8e15432161f452e345ff30c68b0 d.txt
fe4ab8e15432161f452e345ff30c68b0 e.txt

这将打印按md5校验和分组的键值对。

cat table.txt | awk '{print $1}' | sort | uniq  | xargs -i grep {} table.txt
30c68b02161e15435ff52e34f4fe4ab8 b.txt
30c68b02161e15435ff52e34f4fe4ab8 c.txt
fe4ab8e15432161f452e345ff30c68b0 a.txt
fe4ab8e15432161f452e345ff30c68b0 d.txt
fe4ab8e15432161f452e345ff30c68b0 e.txt