次の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
合計を計算するために1回、行を印刷するために1回、2回繰り返す方法はありますか? AWKでこれは可能ですか?それとも別のユーティリティを使用する必要がありますか?
答え1
単一の呼び出しでテーブルを作成するには、次の手順を実行しますawk
。
$ 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%
どのように動作しますか?
ファイルはパラメータとして2回data
提供されます。awk
したがって、2回読み取られます。 1つ目は合計(変数に保存)を取得し、s
2つ目は出力を印刷することです。コマンドの詳細を確認してください。
FNR==NR{s+=$2;next;}
NR は読み取ったレコード (行) の総数であり
awk
、FNR は現在のファイルからこれまで読み取ったレコードの数です。したがって、FNR==NR
私たちは最初のファイルを読んでいます。これが発生すると、変数はs
2番目の列の値だけ増加します。その後、残りのコマンドをスキップして次のレコードから始めるようにnext
指示します。awk
s
0に初期化する必要はありません。では、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
答え2
これを行うための「簡単な」方法は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
今、誰かが何とか気の利いたことを言うと確信しています...
答え3
awkでファイルを開く(完全性のために)
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%
この方法は他の方法よりも多くのメモリを使用しますが、より高速です。
その後、行をarrayとして読み取り、a
フィールド2をarrayとして読み込みますb
。
その後、x
フィールド 2 の値だけ増加します。
最後に、1からレコード数まで繰り返して正しい行を出力し、パーセンテージを計算します。