AWKを使用したブロックの合計(モード変更時の合計の再開)

AWKを使用したブロックの合計(モード変更時の合計の再開)

次のファイルがあります。

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

forsedおよびを使用して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ゼロにリセットします。

おすすめ記事