次のdata
ファイルがあるとします...
foo 10
bar 20
oof 50
rab 20
...列2の合計のパーセントとして列2を印刷するにはどうすればよいですか?つまり、欲しい...
foo 10 10%
bar 20 20%
oof 50 50%
rab 20 20%
...もちろん、それほど明白ではない数字を使用します。積算合計を簡単に作成できますが、どうすればよいかわかりません行を出力する前に合計を計算します。私はこれをawkファイルで行っていますtotals.awk
...
#!/usr/bin/awk -f
BEGIN{
runningtotal=0
}
{
runningtotal=runningtotal+$2
print $1 "\t" $2 "\t" runningtotal "\t" $2/runningtotal
}
したがって、./totals.awk data
利回り...
foo 10 10 1
bar 20 30 0.666667
oof 50 80 0.625
rab 20 100 0.2
2回ループする方法、1回は合計を計算する方法、1回は行を印刷する方法はありますか?これはAWKで可能ですか、それとも他のユーティリティを使用する必要がありますか?
awk
を1回呼び出すだけでテーブルを作成するには:
$ awk 'FNR==NR{s+=$2;next;} {printf "%s\t%s\t%s%%\n",$1,$2,100*$2/s}' data data
foo 10 10%
bar 20 20%
oof 50 50%
rab 20 20%
ファイルdata
は、awk
への引数として2回提供されます。その結果、変数s
に格納されている合計を取得するために1回目、出力を印刷するために2回目に2回読み取られます。コマンドをさらに詳しく見てみましょう:
FNR==NR{s+=$2;next;}
NRはawk
が読み取ったレコード(行)の総数であり、FNRは現在のファイルからこれまでに読み取られたレコードの数です。したがって、FNR==NR
の場合、最初のファイルを読み取っています。これが発生すると、変数s
は2番目の列の値によって増分されます。次に、next
はawk
に残りのコマンドをスキップして次のレコードからやり直すように指示します。
s
をゼロに初期化する必要はないことに注意してください。 awk
では、すべての数値変数はデフォルトでゼロに初期化されます。
printf "%s\t%s\t%s%%\n",$1,$2,100*$2/s
このコマンドに到達すると、2番目のファイルを処理しています。これは、s
が列2の合計を保持することを意味します。したがって、列1、列2、およびパーセンテージ100*$2/s
を出力します。
printf
を使用すると、出力形式を詳細に制御できます。上記のコマンドは、文字列、整数、および浮動小数点に対して機能する%s
形式指定子を使用しています。ここで役立つ他の3つのオプションは次のとおりです。
%d
は、数値を整数としてフォーマットします。数値が実際には浮動小数点の場合、整数に切り捨てられます
%f
は、数値を浮動小数点としてフォーマットします。幅と小数点以下の桁数を%5.2f
などのように指定することもできます。
%e
は指数表記を提供します。これは、いくつかの数値が非常に大きいまたは小さい場合に役立ちます。
これを複数回使用する場合は、長いコマンドを入力するのは不便です。代わりに、コマンドを開く関数またはスクリプトを作成します。
totals
という関数を作成するには、次のコマンドを実行します。
$ totals() { awk 'FNR==NR{s+=$2;next;} {printf "%s\t%s\t%s%%\n",$1,$2,100*$2/s}' "$1" "$1"; }
この関数を定義すると、data
というデータファイルのパーセンテージは次のコマンドを実行して確認できます。
$ totals data
totals
の定義を永続的にするには、~/.bashrc
ファイルに配置します。
スクリプトが必要な場合は、totals.sh
という名前のファイルを作成し、次の内容を含めます。
#!/bin/sh
awk 'FNR==NR{s+=$2;next;} {printf "%s\t%s\t%s%%\n",$1,$2,100*$2/s}' "$1" "$1"
data
というデータファイルのパーセンテージを取得するには、次のコマンドを実行します。
sh totals.sh data
1つのファイルを開いた状態での完全な方法
awk '{a[NR]=$0;x+=(b[NR]=$2)}END{while(++i<=NR)print a[i]"\t"100*b[i]/x"%"}' file
foo 10 10%
bar 20 20%
oof 50 50%
rab 20 20%
これは他よりも多くのメモリを使用しますが、より高速になるはずです
これにより、行が配列a
に読み込まれ、フィールド2が配列b
に読み込まれます。
次に、フィールド2の値だけx
をインクリメントします。
最後に、1からレコード数まで反復し、正しい行を出力してパーセンテージを計算します。
これを行う「単純な」方法は、awk
を2回呼び出すことです。1回で合計を取得し、もう1回で比率を計算します。
$ total=$(awk 'BEGIN{ total=0 } { total=total+$2 } END{ printf total }' data)
$ awk -v total=$total '{ print $1 "\t" $2 "\t" 100*$2/total "%" }' data
誰かがワンライナーをどうにかするだろうと確信しています...