GNU grepの最適化


8

grep -Eパターンファイルでegrep()を使用しています。(-f path/to/file)。

これは、テキストのストリームの無限ループで行われます。これは、すべての入力を一度に累積してgrepに渡すことができないことを意味します(など*.log)。

次の実行で使用するために、grepがPATTERNファイルからビルドしているNFAを「保存」する方法はありますか?

私はグーグルを検索して、運が悪いのでドキュメントを読みました。

もう少し説明しようと思います。IPアドレスやドメインなどの正規表現(質問の一部ではありませんが、別の方法で提案することもできます)を含む文字列の固定数を見つける必要があります。検索はインターネットからのフィードで行われます。あなたはそれをテキストのストリームと考えることができます。grepストリームなので、すべての入力で使用することはできません。ストリームのチャンクを蓄積grepしてそれを使用できます(したがってgrep、各行で使用しません)が、これも制限されています(30秒としましょう)。

私が知っているgrep(ファイルから私の場合には)そのすべてのパターンからNFAを構築しています。したがって、ここでの私の質問はgrep、次の実行のためにそのNFAを変更しないため、保存するように指示できますか?これにより、毎回NFAを構築する時間を節約できます。


で、あなたは何を意味しています。これは、テキストのストリーム上で無限ループで行われますかgrepテキストの1行につき1 つ実行していると言っていますか?テキストはどこから来ていますか?うtail -f選択肢も?
ステファンChazelas

ストリームを30秒間蓄積してから、grepそのチャンクで実行するとします。
bergerg 2017

1
なぜgrep数回実行する必要があるのか​​はまだ明らかではありません。おそらく関連:90万パターンに対して1250文字列のマッチングが非常に遅いのはなぜですか?
ステファンChazelas

5
grepテキストのストリームを処理するためのものですが、いくつかのインスタンスを実行する必要がある理由はまだわかりません。それらすべてを同じgrepインスタンスにフィードできないのはなぜですか?摂食する前にそれらを蓄積する必要があるのはなぜgrepですか?
ステファンChazelas

2
flexを見て、独自のプログラムを作成してください。これにより、はるかに高速になる場合があります。
user2064000

回答:


14

いいえ、そのようなことはありません。一般に、開始grep(新しいプロセスのフォーク、実行可能ファイルのロード、共有ライブラリ、動的リンケージなど)のコストは、正規表現のコンパイルよりもはるかに高いため、この種の最適化はほとんど意味がありません。

なぜ1250文字列を90kパターンと照合するのがとても遅いのか?」いくつかのバージョンのGNU grepで、多数の正規表現で特に遅くなるバグについて。

おそらくここではgrep、チャンクを同じgrepインスタンスにフィードすることで、たとえば、それをコプロセスとして使用し、マーカーを使用して終了を検出することで、何度も実行することを回避できます。zshし、GNU grepawk以外の実装mawk

coproc grep -E -f patterns -e '^@@MARKER@@$' --line-buffered
process_chunk() {
  { cat; echo @@MARKER@@; } >&p & awk '$0 == "@@MARKER@@"{exit};1' <&p
}
process_chunk < chunk1 > chunk1.grepped
process_chunk < chunk2 > chunk2.grepped

それを使って、awkまたはperl代わりに全体を行う方が簡単かもしれませんが。

ただし、grep出力を別のチャンクの別のファイルに入れる必要がない場合は、いつでも実行できます。

{
  cat chunk1
  while wget -qO- ...; done # or whatever you use to fetch those chunks
  ...
} | grep -Ef patterns > output

私はgrepのveraion 3+を持っているのでそれは問題ではありません。フォークのオーバーヘッドさえ考慮しませんでした。私grepはすべてをそのままストリーミングしようと思います。ありがとう。
bergerg 2017

プロセスが終了した後、実行可能ファイルと共有ライブラリはRAMバッファーに残りませんか(OPのRAMが実際に少ない場合を除きます)?
Dmitry Grigoryev 2017

2
@DmitryGrigoryev、はい、おそらく、まだプロセスアドレス空間にマップされ、リンク編集を行う必要があります。ロケールデータの読み込みと解析、オプションの解析、環境などの詳細があります。ポイントは、regcomp()のコストがすべてのオーバーヘッドで希釈されることです。最適化するときに最初に行うことは、最初にいくつかのgrepsを実行しないことです。
ステファンChazelas

1

ストリームなので、すべての入力でgrepを使用できません。ストリームのチャンクを蓄積し、grepを使用できます...

パイプラインがブロックしていることを知っていますか?何かをgrepにパイプし、すべての入力が利用できない場合、grepはそれが利用可能になるまで待機してから、入力がそこにあるかのように続行します。

$ ( echo a1; echo b1; sleep 5; echo a2 ) | grep 'a.'
a1
a2

編集:たとえば、パイプラインがどのように機能するかcmd1 | cmd2は、両方のプログラムが同時に開始され、たとえば65,536バイトの「チャンクバッファ」がその間にあることです。ときにcmd2読み取ろうとすると、そのバッファが空である、それが利用できるようにチャンクを待ちます。ときcmd1試行を書くことと、そのバッファがいっぱいになるまで、待機しますcmd2、それを読み込みます。

私が読み取れるものから、入力をチャンクに切り分けて、それらを個別にgrepに渡す必要はありません。これはすでに自動的に行われています。

EDIT2:grepストリームで結果が見つかるとすぐに結果も印刷する必要があります。結果を得る前にストリームを終了する必要はありません。


0

たぶん、「すべての入力でgrepを使う」ことができますか?nc(netcat)を使用してscript、またはを介して、または他の同様のツールを介して?特に、パターンファイルのサイズが扱いやすい場合(たとえば、正規表現が1000未満の場合)。

最初の例egrepストリーミング接続を行うことができます:(ここではで示されている例ncですが、他の例も適用できます)

prompt:/some/path $ nc somehost someport | egrep -f patternfile | gzip -c - > results.gz

# and while this is running, you can have a look at the growing results.gz:
prompt:/some/otherpath $ tail -f /some/path/results.gz | gzip -c - | less

(注:コマンドをtouch /some/path/results.gz開始する前に、その(空の)ファイルで何も見逃さないようにすることもできます。とにかく、results.gzには、キャッチしたいすべてのものが含まれています。nctail -f

2番目の例egrep現在実行中のシェルセッションでも実行できます(進行状況を追跡する別の方法を示しています)。

#in 1 terminal:
prompt:/home/userA $ script
Script command is started. The file is typescript.
prompt:/home/userA $ 
 ... doing here whatever you want (start IRC? etc) ...
prompt:/home/userA $ ctrl-d # to end the current script session
Script command is complete. The file is typescript.

#and in another terminal, while you are "doing here whatever you want" :
prompt:/home/somewhere $ tail -f /home/userA/typescript | egrep -f patternfile  | tee /some/place/to/store/results.gz

egrepは、grepほとんどのシステムでのの非常に効率的なバージョンです(https://swtch.com/~rsc/regexp/regexp1.htmlのいくつかの重要な情報を参照してください)。


あなたもDD出力、などのようなものでexemple1を使用することができます
オリヴィエ・デュラック

interresting side note:正規表現の既知の部分が大きいほど、grepはより効率的です(たとえば、文字列または正規表現の検索sは非常に多く、マッチングよりも遅くsomething、これはマッチングよりもはるかに遅いですsomething even much longer(後者は、正規表現の一致でより大きいスキップを許可します)巨大なファイルでは、基本的に、解析する時間を長さの比率で「分割」します(つまり、1つの既知の文字をgrepすることは、40の既知の文字の文字列を照合するよりもほぼ40倍遅くなります。それを教授しますが、それは本当に目立ちます。)
Olivier Dulac '11
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.