web-dev-qa-db-ja.com

数千のファイルでのGrep

Cca 26 000ファイルのディレクトリがあり、これらすべてのファイルをgrepする必要があります。問題は、できる限り速くそれを必要とすることです。そのため、grepがfindコマンドから1つのファイルの名前を取得し、一致をファイルに書き込むスクリプトを作成することは理想的ではありません。 「引数リストが長すぎる」問題が発生する前に、このすべてのファイルをgrepするのにcca 2分かかりました。それを行う方法のアイデアはありますか?編集:常に新しいファイルを作成するスクリプトがあるため、すべてのファイルを異なるディレクトリに配置することはできません。

13
user2778979

findの場合:

cd /the/dir
find . -type f -exec grep pattern {} +

-type fregularファイルのみを検索します(通常のファイルを指す場合でもシンボリックリンクも除外します。)ディレクトリ以外の任意のタイプのファイルを検索する場合(ただし、いくつかのタイプのファイルがあることに注意してください)通常は読みたくないfifosまたは/ dev/zeroのように)-type fをGNU固有の! -xtype dに置き換えます(-xtype dは、タイプディレクトリのファイルに一致します).

GNU grep

grep -r pattern /the/dir

(ただし、GNU grepの最新バージョンがない場合は、ディレクトリに降りるとシンボリックリンクをたどります。)-D readオプションを追加しない限り、通常以外のファイルは検索されません。最新ただし、GNU grepのバージョンは、シンボリックリンク内を検索しません。

非常に古いバージョンのGNU findは標準の{} +構文をサポートしていませんでしたが、非標準を使用することができました:

cd /the/dir &&
  find . -type f -print0 | xargs -r0 grep pattern

パフォーマンスはI/Oに依存する可能性があります。つまり、検索を実行する時間は、ストレージからすべてのデータを読み取るのに必要な時間です。

データが冗長ディスクアレイ上にある場合、一度に複数のファイルを読み取るとパフォーマンスが向上する可能性があります(それ以外の場合はパフォーマンスが低下する可能性があります)。パフォーマンスがI/Oバウンドではなく(たとえば、すべてのデータがキャッシュにあるため)、複数のCPUがある場合は、同時grepsも役立つ可能性があります。 GNU xargs-Pオプションでそれを行うことができます。

たとえば、データが3つのドライブを持つRAID1アレイ上にある場合、またはデータがキャッシュ内にあり、時間に余裕のある3つのCPUがある場合:

cd /the/dir &&
  find . -type f -print0 | xargs -n1000 -r0P3 grep pattern

(ここでは、-n1000を使用して、1000ファイルごとに新しいgrepを生成します。一度に3つまで並列で実行されます)。

ただし、grepの出力がリダイレクトされる場合は、3つのgrepプロセスからの出力が正しくインターリーブされないことに注意してください。この場合、次のように実行できます。

find . -type f -print0 | stdbuf -oL xargs -n1000 -r0P3 grep pattern

(最近のGNUまたはFreeBSDシステム)またはGNU grep--line-bufferedオプションを使用します。

patternが固定文字列の場合、-Fオプションを追加すると問題が改善する可能性があります。

マルチバイト文字データでない場合、またはそのパターンのマッチングの場合、データがマルチバイト文字かどうかは関係ありません。

cd /the/dir &&
  LC_ALL=C grep -r pattern .

パフォーマンスを大幅に向上させることができます。

このような検索を頻繁に行う場合は、そこにある多くの検索エンジンの1つを使用してデータにインデックスを付けることができます。

19

単一のディレクトリにある26000個のファイルは、ほとんどのファイルシステムにとって大量です。時間のかなりの部分がこの大きなディレクトリの読み取りに費やされている可能性があります。それを数百のファイルだけの小さなディレクトリに分割することを検討してください。

findを呼び出しても、間違っていない限り、パフォーマンスの低下を説明できません。これは、ディレクトリをトラバースする高速な方法であり、長すぎるコマンドラインを実行しようとするリスクを冒さないようにするためです。コマンドの呼び出しごとにできるだけ多くのファイルをパックする-exec grep PATTERN {} +を使用してください。ファイルごとにgrepを1回実行する-exec grep PATTERN {} \;は使用しないでください。ファイルごとに1回コマンドを実行するのはかなり遅くなる可能性があります。

すべてのファイルを複数回grepする必要がある場合(前述のように、スクリプトを実行します)、ramディスクを調べ、そこにすべてのファイルをコピーしてから、ファイルを複数回grepすることをお勧めします。これにより、検索が高速化されます。少なくとも100倍。

十分なRAMが必要です。それ以外の場合は、ファイルのインデックス作成を検討する必要があります。 luceneまたはnosqlデータベースに入れてから、クエリを実行します。

0