我有一个包含这样的数据的大文件:
a 23 b 8 a 22 b 1
我想能够得到这个:
a 45 b 9
我可以先对这个文件进行sorting,然后通过扫描文件来完成。 什么是一个好的直接的命令行方式呢?
awk '{ arr[$1]+=$2 } END { for (key in arr) printf("%s\t%s\n", key, arr[key]) }' file \ | sort +0n -1
我希望这有帮助。
这里不需要awk,甚至不需要排序 – 如果你有Bash 4.0,你可以使用关联数组:
#!/bin/bash declare -A values while read key value; do values["$key"]=$(( $value + ${values[$key]:-0} )) done for key in "${!values[@]}"; do printf "%s %s\n" "$key" "${values[$key]}" done
…或者,如果你首先对文件进行排序(这将更有效地利用内存; GNU排序能够做技巧来对大于内存的文件进行排序,这是一个天真的脚本 – 无论是在awk,python还是shell中)不会),你可以这样做的方式,将在旧版本(我期望以下工作通过bash 2.0):
#!/bin/bash read cur_key cur_value while read key value; do if [[ $key = "$cur_key" ]] ; then cur_value=$(( cur_value + value )) else printf "%s %s\n" "$cur_key" "$cur_value" cur_key="$key" cur_value="$value" fi done printf "%s %s\n" "$cur_key" "$cur_value"
这个Perl单线程似乎做的工作:
perl -nle '($k, $v) = split; $s{$k} += $v; END {$, = " "; foreach $k (sort keys %s) {print $k, $s{$k}}}' inputfile
一种使用perl
:
perl -ane ' next unless @F == 2; $h{ $F[0] } += $F[1]; END { printf qq[%s %d\n], $_, $h{ $_ } for sort keys %h; } ' infile
infile
内容:
a 23 b 8 a 22 b 1
输出:
a 45 b 9
GNU awk (版本小于4):
WHINY_USERS= awk 'END { for (E in a) print E, a[E] } { a[$1] += $2 }' infile
用GNU awk > = 4:
awk 'END { PROCINFO["sorted_in"] = "@ind_str_asc" for (E in a) print E, a[E] } { a[$1] += $2 }' infile