非常に大きなファイルに対して以下の2つのコマンドを実行しました
grep -E 'string1|string2' 151103*.log|grep 'string3' | grep string4
awk '/string1|string2/ && /string3/ && /string4/' 151103*.log
実行にはほぼ同じ時間がかかりました。しかし、awk
一致する結果を表示するのがはるかに速くなりました。grep
プロセスが完了したときに、最後に同じ結果が表示されました。
awk
どちらのプロセスも完了するまでに同じ時間がかかりました。との両方の検索の背後にあるロジックを知りたいだけですgrep
。
なぜawk
速いのですか? 両方のプログラムの検索ロジックは異なりますか? 上記の検索で文字列を混ぜると、検索速度に違いが生じますか?
答え1
GNU はgrep
出力をバッファリングしますが、GNU はawk
そうしません。また、GNU を使用せずawk
、他のバリアントを使用していたとしても、端末に印刷している場合は行バッファリングされる可能性が高く、\n
新しい行が発生するたびに出力がフラッシュされますが、grep
パイプに書き込むため、いずれにせよブロックバッファリングされます。GNU をお持ちの場合は、比較にgrep
使用してgrep --line-buffered ... | grep ...
結果をすばやく確認できます。実質的にすべての一致テスト、特に GNU にgrep
勝る可能性が高いです。awk
grep
sed
あなたが望むことを実行するための方法は次のとおりです。
sed -ne'/string4/{/string3/s/string[12]/&/p;}' <in >out
答え2
grep パイプラインは、grep
文字列 4 の最終部分が何かに一致するまで何も出力できず、前のパイプ バッファがいっぱいになった後にのみ入力を取得します。関連する質問を参照してください。パイプバッファの大きさはどれくらいですか?そしてパイプ内のバッファリングをオフにする。
入力内の文字列の頻度に応じて、静的検索を最初に配置して拡張正規表現を調べる量を減らすことで、実行時間の違いがわかる場合があります。
答え3
awk の例では、正規表現検索全体を 1 回のパスで実行しています。入力の各行で、最初、2 番目、3 番目の正規表現が見つかった場合、その行が印刷され、基本的にすぐに (一致する行の処理後) 出力が表示されます。
grep の例では、同じことを実行するのに 3 つの異なる grep 呼び出し (正規表現ごとに 1 つ) を使用していますが、各呼び出しの出力が次の呼び出しの入力になるため、次の呼び出しで処理する前に各呼び出しを完了する必要があります。
1000 行のファイルが 1 つあり、5 行目だけが 3 つの正規表現すべてに一致した場合、awk コマンドは 5 行目を処理した後、6 行目を処理する前に出力を表示します。これをパイプされた grep ステートメントと比較してください。1 回目の grep 呼び出しでは、5 行目と、1 回目の正規表現に一致する可能性のあるその他の行が検索され、入力の 1000 行目 (最終行) が処理された後、その出力が 2 回目の grep 呼び出しの入力になります。2 回目の grep 呼び出しでは、1 回目の出力の行数を処理し、1 回目と 2 回目の正規表現の両方に一致する行を出力します。これが 3 回目の grep 呼び出しの入力になります。3 回目の grep 呼び出しで各行が処理されるにつれて、その正規表現に一致する行が出力されます。
上記の例について、grep の最良ケースと最悪ケースを比較することができます。5 行目 (5 行すべてに一致) を除いて、どの行も正規表現に一致しない場合、最初の grep は 1000 行、2 行目は 1 行、3 行目は 1 行を処理します。つまり、出力が出るまでに 1002 行を処理します (最良のケース)。すべての行が最初の 2 つの正規表現に一致し、3 行目と一致する行が 1 行だけの場合、パイプされた grep 構造は、5 行目で一致を見つけて何らかの出力を得るまでに 1000 + 1000 行 + 5 = 2005 行を処理します (2 行目の grep 出力から残りの 995 行の処理は続行されますが、他に一致する行がないため、それ以上の出力は表示されません)。
これを awk コマンドと比較すると、各行で 3 つの正規表現を同時にチェックし、5 行目を処理した後に出力が表示されます。同時にチェックするファイルが増えるほど、その違いは顕著になります。
たとえば、上記のようにすべてのファイルに対して grep コマンドを同時に実行する代わりに、出力がより速く表示されるかどうかを比較します (理論的にはそうすべきですが、ファイル全体でのヒットの分布に応じて結果が異なる場合があります)。
grep -E 'string1|string2' 151103*.log|grep 'string3' | grep string4
代わりに、次のように各ファイルに対して一連の grep コマンドを個別に実行します。
for i in 151103*.log;
do grep -E 'string1|string2' $i |grep 'string3' | grep string4;
done
これでも awk ステートメントほど速く出力は生成されませんが、違いがわかるかもしれません。
答え4
grep、awk、sed は同様のタスクに使用できますが、それぞれに長所と短所があります。
Awk は、表形式のデータや計算などを実行する必要がある場合に最適です。
Sed はテキストの置換に優れています。
grep は入力データから行を選択するのに最適であるため、このタスクでは awk よりも高速であると予想していました。おそらく、3 つの grep コマンドを 1 つにまとめると、そのようになるでしょう。現時点では、grep は 3 回開始する必要があり、2 回目と 3 回目は最初のコマンドからの入力を待つ必要があるため、不利です。結果に遅延が生じるのは、これが理由かもしれません。ただし、それについてはよくわかりません。