我有一个文件,其中有几行重复的行,仅第一列有所不同。
原始文件:
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
使用datamash
和awk
:
由于重复行仅在第一列中有所不同,因此该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 '...'
。