awkとgrepの比較

awkとgrepの比較

非常に大きなファイルに対して、次の2つのコマンドを実行しました。

grep -E 'string1|string2' 151103*.log|grep 'string3' | grep string4

awk '/string1|string2/ && /string3/ && /string4/' 151103*.log

実行時間はほぼ同じです。しかし、awk一致する結果がより早く現れました。grepまた、同じ結果が表示されますが、最後に処理が完了します。

どちらのプロセスも同じ時間がかかり、検索とawkその背後にあるロジックが気になりますgrep

なぜより速いのですawkか?これら2つのプログラムは異なる検索ロジックを持っていますか?上記の検索で文字列を難読化すると、検索速度に影響しますか?

答え1

GNUはgrep出力をバッファリングしますが、GNUはawkバッファリングしません。 GNUを使用せずにawk他のバリアントを使用しても、端末に印刷するとまだラインバッファリングされているため、\newlineの出力は発生するたびにフラッシュされますが、grepパイプに書き込むとブロックされます。バッファが何であれ。 GNUがある場合は、これをgrep使用grep --line-buffered ... | grep ...して比較してできるだけ早く結果を確認できます。おそらく、grepほぼすべての競争テストawk、特にGNUで勝つでしょうgrep

これsedもあなたが望むことを行います:

sed -ne'/string4/{/string3/s/string[12]/&/p;}' <in >out

答え2

grepパイプは、string4の最後のエントリが何かと一致するまで何も出力できず、古いパイプgrepバッファがいっぱいになった後にのみ入力を受け取ります。関連質問を見るパイプバッファはどれくらい大きいですか?そしてパイプラインでバッファリングをオフにする

入力の文字列の頻度に応じて、静的検索を最初に配置して、拡張正規表現を表示する回数を減らすことで、ランタイムの違いを確認できます。

答え3

あなたのawkの例は、完全な正規表現検索を一度に実行します。各入力行について、最初、2番目、および3番目の正規表現が見つかると、その行が印刷され、出力がすぐに表示されます(一致する行が処理されます)。

grepの例では、同じ操作を実行するために3つの異なるgrep呼び出し(各正規表現に対して1つ)を使用しますが、各呼び出しの出力は次の呼び出しの入力になります。つまり、各呼び出しは処理する前に呼び出しを完了する必要があります。 。

1000行のファイルがあり、5行だけが3つの正規表現のすべてと一致する場合、awkコマンドは5行が処理されてから6行が処理される前に出力を提供します。これをパイプラインのgrepステートメントと比較してください。 grepの最初の呼び出しは行5と最初の正規表現と一致する可能性がある他のすべての行を探し、入力の1000行目(最後の)行を処理した後、出力はgrep入力の2番目の呼び出しになります。 grepへの2番目の呼び出しは、最初の出力の行と同じように処理し、最初と2番目の正規表現に一致する行を出力します。その後、grepへの3回目の呼び出しの入力になります。各行を処理するために grep が 3 番目に呼び出されると、正規表現に一致するすべての行が出力されます。

上記の例では、grepの最高のケースと最悪のケースを比較できます。行5以外の正規表現に一致する行がない場合(5行すべて一致)、最初のgrepは1000行を処理し、2番目の1 grepは1行を処理し、3番目のgrepは1行を処理します。 。出力を生成する前に1002行(最良の場合)を処理します。すべての行が最初の2つの正規表現と一致するが、1行だけが3番目の正規表現と一致する場合、パイプラインのgrep設定は5行と一致する項目を見つける前に1000 + 1000行+ 5 = 2005行を処理し、いくつかの出力を生成しますします。 2番目のgrep出力には残りの995行がありますが、一致するものがないため、出力は表示されなくなります。

これを各行の3つの正規表現を同時に確認し、行5を処理して出力を提供するawkコマンドと比較します。同時に、より多くのファイルを確認するほど、違いは大きくなります。

たとえば、上記と同時にすべてのファイルに対して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番目は最初の入力を待つ必要があるため、不利な状況に直面しています。これは、結果が遅れる理由を説明できます。それでもそれはよくわかりません。

関連情報