複数の重複行を持つファイルがあり、最初の列のみが異なります。
ソースファイル:
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
2番目の列を並べ替えるには、追加してください。
出力:
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 '...'
。