根据匹配字段对列求和

Tom*_*Pio 11 awk text-processing sort uniq

我有以下格式的大文件:

2 1019 0 12 
2 1019 3 0 
2 1021 0 2 
2 1021 2 0 
2 1022 4 5
2 1030 0 1 
2 1030 5 0 
2 1031 4 4
Run Code Online (Sandbox Code Playgroud)

如果第2 列中的值匹配,我想对两行的第3 列和第4中的值求和,否则只是唯一行中值的总和。

所以我希望的输出看起来像这样:

2 1019 15 
2 1021 4 
2 1022 9 
2 1030 6 
2 1031 8
Run Code Online (Sandbox Code Playgroud)

我可以根据第2 列使用awk或对文件进行排序,sort并使用 对最后一列求和awk,但仅适用于个别行,而不适用于第 2匹配的两行。

ter*_*don 12

我会在 Perl 中这样做:

$ perl -lane '$k{"$F[0] $F[1]"}+=$F[2]+$F[3]; 
              END{print "$_ $k{$_}" for keys(%k) }' file 
2 1019 15
2 1021 4
2 1030 6
2 1031 8
2 1022 9
Run Code Online (Sandbox Code Playgroud)

或者 awk:

awk '{a[$1" "$2]+=$3+$4}END{for (i in a){print i,a[i]}}' file 
Run Code Online (Sandbox Code Playgroud)

如果您希望根据第二列对输出进行排序,您可以直接通过管道传输到sort

awk '{a[$1" "$2]+=$3+$4}END{for (i in a){print i,a[i]}}' file | sort -k2
Run Code Online (Sandbox Code Playgroud)

请注意,这两种解决方案也包括第一列。这个想法是使用第一列和第二列作为散列(在 perl 中)或关联数组(在 awk 中)的键。每个解决方案的关键是column1 column2,如果两行具有相同的第二列但不同的第一列,则它们将分别分组:

$ cat file
2 1019 2 3
2 1019 4 1
3 1019 2 2

$ awk '{a[$1" "$2]+=$3+$4}END{for (i in a){print i,a[i]}}' file
3 1019 4
2 1019 10
Run Code Online (Sandbox Code Playgroud)


tal*_*zin 7

也许这会有所帮助,但第 1 列是否始终为 2,结果是否取决于它?

awk '{ map[$2] += $3 + $4; } END { for (i in map) { print "2", i, map[i] | "sort -t't'" } }' file
Run Code Online (Sandbox Code Playgroud)

或者正如glenn jackman在关于排序的评论中提到的:

gawk '{ map[$2] += $3 + $4; } END { PROCINFO["sorted_in"] = "@ind_str_asc"; for (i in map) { print 2, i, map[i] } }' file
Run Code Online (Sandbox Code Playgroud)

  • 如果您有 GNU awk,请使用 `PROCINFO["sorted_in"] = "@ind_num_asc"` 而不是管道到 `sort`。参考 https://www.gnu.org/software/gawk/manual/html_node/Controlling-Scanning.html#Controlling-Scanning (2认同)