awkを介して列項目を処理するのに役立ちます。私が試したいことは次のとおりです。
- ユーザー定義のブロックサイズで列を分割します。
- 各ブロックの各項目が計算され合計され、各項目の平均が最終ブロックサイズになります。
たとえば、以下はリストです。
1
2
3
4
5
6
7
8
9
10
11
12
ここではブロックサイズ4を使いたいですが(私の場合は状況によって異なるかもしれません)。
- ブロック1
1 2 3 4
- ブロック2
5 6 7 8
- ブロック3
9 10 11 12
処理後、
5
6
7
8
これは、すべてのブロックで1、2、3、4位のアイテムの平均です。
答え1
次のawk
プログラムがこれを行います。データがdata.txt
最初の列に保存されているとします(ただし、他の列に簡単に適用できます)。また、空の列はなく、完全なブロックしかないとします。
awk -v cs=4 '{if ((i=NR%cs)==0) {n_ch++; i=cs};buf[i]+=$1;} END{for (i=1;i<=cs;i++) printf "%d\n",buf[i]/n_ch}' data.txt
awk
ブロックサイズは文を介して渡されます。-v cs=size
各行について、「ブロック内の項目番号」を決定し、を渡してi
項目
i = "line number" modulo "chunk size"
を配列に合計しますbuf
。ブロックが完了するたびにブロックカウンタがn_ch
インクリメントされます。
最後に、すべてのアイテム数の平均を印刷します。
答え2
awk -v cs=4 '
BEGIN {
"(wc -l <" ARGV[1] ")" | getline nl
nc = sprintf("%d", nl/cs)
}
{ a[NR%cs] += $1 }
NR>nl-cs { print a[NR%cs]/nc }
' file
5
6
7
8
- 開始ブロックでファイルの行を決定し、それをnl変数に保存します。
- その後、ブロック数を取り、nc変数に保存します。
- 累積合計を配列インデックスモジュールとして行番号 % ブロックサイズに累積します。
- その後、行番号がnl-csのしきい値を超えると(最後のブロックに入るという意味)、結果の印刷が開始されます。
または、ファイルの長さとブロック数を事前に計算したくない場合は、次のようにします。
awk -v cs=4 '
{ a[NR] = $1 }
END {
for (i=1; i<=cs; i++) {
k = s = 0
for (j=i; j<=NR; j+=cs) {
s += a[j]; k++
}
print s/k
}
}
' file
答え3
別のアプローチawk
は、実行中に各ブロックの要素を計算することです。したがって、レコード数がブロックの正確な倍数ではない場合でも、まだ平均です。
awk -v ch=4 '{k=(NR-1)%ch; n[k]++; un[k]+=$1}
END{for (k in un) print "Line "k+1" has "n[k]" elements totalling "un[k]" and average "un[k]/n[k]}' file
Line 1 has 3 elements totalling 15 and average 5
Line 2 has 3 elements totalling 18 and average 6
Line 3 has 3 elements totalling 21 and average 7
Line 4 has 3 elements totalling 24 and average 8
END
説明的である必要はありませんが、
END{for (k in un) print un[k]/n[k]}' file
5
6
7
8
出力順序を保証したい場合
END{for (k=0; k<ch; k++) print un[k]/n[k]}' file