次のファイルがあります。
A 100
A 200
A 300 #sum=600
B 400
B 500 #sum=900
A 600
A 700
A 800 #sum=2100
私は出力が次のようになります:
A 600
B 900
A 2100
C sum_of_C
D sum_of_D
for
、sed
およびを使用してgrep
これを行うことができますawk
。
ところで勉強中だから台本awk
を書きたいですawk
。これまで私は以下を持っています:
if (${NR {print $1}} == ${NR-1 {print $1}})
sum+=$2
print $0"\t"sum
else
sum=$2
print $0"\t"sum
awk -f awkscript file
成功しませんでした。解決策は何ですか?
答え1
if
あなたがそこで何をしたいのかわかりません。目標の場合、フィールド数NR
に使用されるレコード数。これらの真ん中にブロックをNF
配置することはできません。{}
あなたの目標は、この行のフィールド値を前の行のフィールド値と比較し、新しいデータ「グループ」に達したときに合計を印刷することです。その場合、このスクリプトはあなたが望むことを行い、あなたの目標とほぼ同じだと思います。
{
if (last && $1 != last) {
print last, sum
sum = 0
}
sum = sum + $2
last = $1
}
END {
print last, sum
}
last
前の行の最初のフィールド()値を保持する新しい変数を作成します。$1
私たちはこれを見て、私たちが見ているグループを追跡するために使用します。
{ ... }
各行に対して(最上位レベルにあるため)最初にa)がlast
設定されているか(最初の行に何も印刷しないため)、b)最初のフィールドの値がlast
。そうであればlast
、値、空白、,
計算sum
された内容を印刷します。 (タブをご希望の場合は"\t"
先ほど引用符で囲んで使用してください)- 印刷後、
sum
ゼロにリセットされます。 $2
どちらにしても、2番目のフィールド()の値をに追加しますsum
。- 各行に最初のフィールド(グループ)を保存することで、
last
次の行の比較に使用できます。 - 最後に、最後のグループを印刷しようとしています。この目的のために、我々は
END { ... }
ブロックを使用します。データが不足すると、プログラムの終了時に実行されます。以前のように、合計で作業しているグループを印刷します。
私が実行した場合:
awk -f sum.awk < data
あなたのデータファイルを使用して、次のような結果を得る。
A 600
B 900
A 2100
予想通り。
awkでも別の方法でも、これを行うより簡単な方法があります。特に、上記の本文を次のように置き換えることができます。
last && $1 != last {
print last, sum
sum = 0
}
{
sum = sum + $2
last = $1
}
ここでは、明示的なテストの代わりにawkの条件付きブロック構文を使用しますif
。プログラムは上記と同じように動作しますが、より慣用的です。この例には大きな違いはありませんが、awkを学んでいるかどうかを知っておくと便利です。
#sum=
提供されたファイルの例が実際に行(または同様のもの)を持つファイルの例である場合は、次のスクリプトを使用できます。
{
sum = sum + $2
if (NF == 3) {
print $1, sum
sum = 0
}
}
各行に対して、2番目のフィールドの値をsum
変数に追加します。正確に3つのフィールド(NF == 3
)を含む行から合計を印刷し、sum
ゼロにリセットします。
答え2
ファイルがすべての合計をメモリに格納できるほど小さい場合は、次のように簡単な操作を実行できます。
$ awk '{sum[$1]+=$2}END{for(pat in sum){print pat,sum[pat]}}' file
A 2700
B 900
これはコメントスクリプトと同じですawk
。
#!/usr/bin/awk -f
{
## Here, we use $1 as the key of an associative array
## and increment its current value by $2. The result of
## this will be an array element for each different $1 in
## the file whose value will be the sum of all associated $2s.
sum[$1]+=$2
}
## The END{} block is exacuted after the entire file
## has been processed.
END{
## Iterate through the keys of the array (the $1s),
## saving each as 'pat'. Then, print the current value of
## 'pat' as well as the associated value (the sum) from
## the array.
for(pat in sum){
print pat,sum[pat]
}
}
このアプローチで発生する可能性のある唯一の問題は、行が多すぎるとs配列を維持すると$1
メモリが不足することです。現代のシステムでは、このようなことが起こる可能性はほとんどありません。一方、この方法はソートされていないファイルを処理できるため、ファイルの行が順番にソートされていない場合でも機能します。