
awk
最後のデータポイントに基づいて正規化するために使用したいデータファイルがあります。したがって、最後のデータポイントに最初にアクセスしてデータを正規化してから、正常に処理したいと思います。
2回使用される次の方法はtac
タスクを実行しますが、おそらく必要なものよりも複雑です。
$ cat file
0 5
1 2
2 3
3 4
$ tac file | awk 'NR==1{norm=$2} {print $1, $2/norm}' | tac
0 1.25
1 0.5
2 0.75
3 1
私の質問は:awkだけを使用して上記の結果を得ることができますか?
私は答えが「いいえ、awkはファイルを1行ずつスキャンします」と思いますが、代替案の提案に開いています。
答え1
データソースが複数回読み取ることができるファイルである場合(つまり、ストリームではない場合)、最初をtail(1)
使用して最後の行から目的のデータを取得し、次にawkに渡して順番に処理する必要があります。tail
ファイルの前のすべてのデータを読み取らずに最後の行を読み取るには、ファイルの終わりを調べます。
awk -v norm=$(tail -n 1 file | cut -d' ' -f2) '{print $1, $2/norm}' file
これは、ファイル全体がバッファキャッシュに収まらない(つまり、パスごとに1回ずつディスクから2回読み取る必要があることを意味します)、大容量ファイルにとって大きな利点であり、スキャンしなくてもある程度役に立ちます。入力が最後の行に達します。より小さいファイルは、2段階の方法と大きく異なることはありません。
答え2
awkから2段階のソリューションでこれを行うことができます。
awk 'FNR == NR { n = $2; next } { print $1, $2/n }' infile infile
あなたのawkバージョンがENDFILEブロック(例:GNU awk 4+)をサポートしている場合は、次のことができます。
awk 'ENDFILE { n = $2 } FNR != NR { print $1, $2/n }' infile infile
seek
ファイルの終わりを最初に見るのがより効率的であることに注意してください。カムの答え。
説明する
最初の例は、$2
ローカル行カウンタ()FNR
がグローバル行カウンタ()と同じNR
場合にのみ計算されるという前の内容を覚えて動作します。コマンドnext
は次の行に移動します。この場合、2番目の引数が解析されたときにのみ最後のブロックが評価されるようにします。
2 番目の例は同様のロジックを持っていますが、入力ファイルの終わりに達すると評価される ENDFILE ブロックを利用します。
答え3
配列にロードして逆さまに読み取ることができます。
awk '{x[i++]=$0} END{for (j=i-1; j>=0;) print x[j--] }'
これはより効率的に実行できますが、これはawk
なぜ正しいツールではないのかを示しています。可能であれば、引き続き使用すると、tac
GNU tacは通常、作業に使用されるさまざまなツールの中で最も高速です。