使用 awk 根据该行的其余部分对第一列中的值求和

使用 awk 根据该行的其余部分对第一列中的值求和

我有一个文件,其中有几行重复的行,仅第一列有所不同。

原始文件:

2 A 3 rr 44 5 t y uuu 8
3 A 3 rr 44 5 t y uuu 8
0 B f 1
1 C 6 5 55 yy 7 4 3 4-5 tt efvho 44 3 5 gg 5  4 t rr 33
5 C 6 5 55 yy 7 4 3 4-5 tt efvho 44 3 5 gg 5  4 t rr 33
5 C 6 5 55 yy 7 4 3 4-5 tt efvho 44 3 5 gg 5  4 t rr 33
3 D tt v 44 f1 p
1 D tt v 44 f1 p

我想要的是去掉重复项并对第一列中的值求和。

期望的输出:

5 A 3 rr 44 5 t y uuu 8
0 B f 1
11 C 6 5 55 yy 7 4 3 4-5 tt efvho 44 3 5 gg 5  4 t rr 33
4 D tt v 44 f1 p

这个脚本非常接近我想要做的事情:

awk  '{a[$2]+=$1}END{for(i in a)print a[i] , i |"sort"}' file

给出这个输出:

5 A 
0 B 
11 C 
4 D 

有没有办法将 $2 更改为该脚本中除第一列之外的所有列?

答案1

这可以工作,但不会保持行的顺序:

awk '{v=$1; $1=""; s[$0]=s[$0]+v} END {for (r in s) { printf "%s%s\n",s[r],r }}' file
  • 将第一个字段保存在变量中,然后清空它。
  • 保存一个数组,其中行(已清空$1)作为键,并将保存的总和$1作为其值。
  • 最后,打印数组。我用来printf避免出现额外的空间,因为我们无法删除,而只能为空$1

添加| sort -k2以对第二列进行排序。

输出:

5 A 3 rr 44 5 t y uuu 8
0 B f 1
11 C 6 5 55 yy 7 4 3 4-5 tt efvho 44 3 5 gg 5 4 t rr 33
4 D tt v 44 f1 p

答案2

使用datamashawk

由于重复行仅在第一列中有所不同,因此该datamash命令可以工作。

$ datamash -s -t' ' groupby 2 sum 1 --full <file | 
awk '{$1=$NF; NF -= 1}1'

答案3

一次仅在内存中存储 1 行,并使用任何 awk 在输出中再现输入顺序:

$ cat tst.awk
{
    currKey = $0
    sub(/[^[:space:]]+ /,"",currKey)
}
currKey != prevKey {
    if ( NR > 1 ) {
        print prev0
    }
    prevKey = currKey
    prev1 = 0
}
{
    $1 += prev1
    prev1 = $1
    prev0 = $0
}
END {
    print prev0
}

$ awk -f tst.awk file
5 A 3 rr 44 5 t y uuu 8
0 B f 1
11 C 6 5 55 yy 7 4 3 4-5 tt efvho 44 3 5 gg 5 4 t rr 33
4 D tt v 44 f1 p

上面假设您的重复行被分组在一起。如果不是就跑sort -k2 file | awk '...'

相关内容