再帰 grep と find/-type f -exec grep{}\;どちらがより効率的で速いですか?

再帰 grep と find/-type f -exec grep{}\;どちらがより効率的で速いですか?

ファイルシステム全体で文字列を含むファイルを見つけるために、再帰的なgrepとgrepを使用してexecステートメント内で検索する方が効率的ですか?ファイル拡張子やファイル名と一致する正規表現を知っていれば、少なくともフィルタリングを実行できますが、-type fどちらが良いかを知ることができるので、 find がより効率的であると思います。 GNU grep 2.6.3;検索(GNU findutils)4.4.2

例:

grep -r -i 'the brown dog' /

find / -type f -exec grep -i 'the brown dog' {} \;

答え1

私は全く知りません:

grep -r -i 'the brown dog' /*

それがまさにあなたが意味したものです。これは、隠されていないすべてのファイルとディレクトリに対して繰り返しgrepを実行することを意味します/(ただし、まだその中にある隠しファイルとディレクトリを見てください)。

あなたが意味すると仮定すると:

grep -r -i 'the brown dog' /

参考にするいくつかの点があります。

  • すべてのgrep実装がこれをサポートする-rわけではありません。いくつかは、ディレクトリツリーをナビゲートするときにディレクトリのシンボリックリンクに従います(これは同じファイルを何度も表示することも、ループで無限に実行されることもあります)。 'ティー。一部はデバイスファイル(たとえばかなり長い時間がかかります/dev/zero)やパイプやバイナリを見ていますが、一部はそうではありません。
  • grepファイルが見つかるとすぐにファイル内を検索し始めるので、うまく機能します。ただし、ファイルを検索すると、検索するファイルはもう見つかりません(ほとんどの場合も同様です)。

あなたの:

find / -type f -exec grep -i 'the brown dog' {} \;

-rここでは言葉にならないものを削除しました。)grepファイルごとに1つずつ実行するので、非常に非効率的です。;1つの引数のみを許可するコマンドでのみ使用できます。そして、ここではgrep1つのファイルしか探していないので、ファイル名は印刷されないので、一致するものがどこにあるのかわかりません。

デバイスファイル、パイプ、シンボリックリンクを見ず、シンボリックリンクに従わないが、それでも/proc/mem

find / -type f -exec grep -i 'the brown dog' {} +

grepできるだけ少ないコマンドが実行されるため、はるかに優れています。最後の実行にファイルが1つしかない場合は、ファイル名を取得します。これを行うには、以下を使用するのが最善です。

find / -type f -exec grep -i 'the brown dog' /dev/null {} +

またはGNUを使用してくださいgrep

find / -type f -exec grep -Hi 'the brown dog' {} +

処理するのに十分なファイルが見つかるまで開始されないため、grep初期遅延が発生します。findそして、find古いファイルが返されるまで、より多くのファイルの検索は続行されません。grep大きなファイルのリストを割り当てて渡すことはわずかな(おそらく無視できる)影響を与えるため、全体的にgrep -rシンボリックリンクに従わないか、デバイス内のファイルを見ないよりも効率が悪くなる可能性があります。

GNUツールの使用:

find / -type f -print0 | xargs -r0 grep -Hi 'the brown dog'

上記のように、できるだけ少ないインスタンスが実行されますが、最初のgrepバッチ内で最初にルックアップを呼び出すと、より多くのfindファイルが引き続き見つかります。grepしかし、これが利点かもしれないし、そうでないかもしれません。たとえば、データが回転しているハードドライブに保存されている場合、ディスク上の他の場所に保存されているデータにfindアクセスすると、ディスクヘッドが継続的に移動し、ディスクスループットが低下します。これはgrepRAID設定(他のディスクにアクセスfindできるgrep)またはSSDに良い影響を与える可能性があります。

RAID設定で複数実行同時に grep電話をかけると状況が改善する可能性があります。まだ3つのディスクRAID1ストレージでGNUツールを使用しています。

find / -type f -print0 | xargs -r0 -P2 grep -Hi 'the brown dog'

パフォーマンスが大幅に向上する可能性があります。ただし、grep最初のコマンドを入力するのに十分なファイルが見つかるまで、2番目のgrepコマンドは開始されません。このタスクがより速く実行されるように(および呼び出しごとに少ないファイル数を渡すように)-nオプションを追加できます。xargsgrep

xargsまた、出力をターミナルデバイス以外のものにリダイレクトすると、grepssは出力バッファリングを開始します。これはgrep、対応するsの出力が誤ってインターリーブされる可能性があることを意味します。 (GNUまたはFreeBSDで利用可能な場合)(非常に長い行(通常4KiB以上)のためにまだ問題がある可能性があります)を使用してこの問題を解決するか、stdbuf -oL各出力を別々のファイルに書き込んで最後にすべて接続する必要があります。

ここで探している文字列は固定されているので(正規表現ではない)、そのオプションを-F使用すると影響を受ける可能性があります(grep実装の最適化方法は既にわかっているため、可能性は低くなります)。

大きな影響を与えるもう1つの方法は、ロケールをCに変更することです(マルチバイトロケールにある場合)。

find / -type f -print0 | LC_ALL=C xargs -r0 -P2 grep -Hi 'the brown dog'

/proc/sys...内部を見たくない場合は、-xdev検索するファイルシステムを使用して指定します。

LC_ALL=C find / /home -xdev -type f -exec grep -i 'the brown dog' /dev/null {} +

または、明示的に除外するパスをトリミングします。

LC_ALL=C find / \( -path /dev -o -path /proc -o -path /sys \) -prune -o \
  -type f -exec grep -i 'the brown dog' /dev/null {} +

答え2

*呼び出しが重要でない場合は、インスタンスが1つだけ起動され、フォークが無料ではないgrepため、最初の呼び出しはより効率的です。grepほとんどの場合、使用すると速度が速くなりますが、*極端な場合はソートを使用すると状況が反転する可能性があります。

特に小さなファイルが多い場合は、よりうまく機能する他のfind構造があるかもしれません。grep一度に多数のファイルエントリとinodeを読み取ると、回転メディアのパフォーマンスが向上する可能性があります。

しかし、システムコールの統計を見てみましょう。

探す

> strace -cf find . -type f -exec grep -i -r 'the brown dog' {} \;
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 97.86    0.883000        3619       244           wait4
  0.53    0.004809           1      9318      4658 open
  0.46    0.004165           1      6875           mmap
  0.28    0.002555           3       977       732 execve
  0.19    0.001677           2       980       735 stat
  0.15    0.001366           1      1966           mprotect
  0.09    0.000837           0      1820           read
  0.09    0.000784           0      5647           close
  0.07    0.000604           0      5215           fstat
  0.06    0.000537           1       493           munmap
  0.05    0.000465           2       244           clone
  0.04    0.000356           1       245       245 access
  0.03    0.000287           2       134           newfstatat
  0.03    0.000235           1       312           openat
  0.02    0.000193           0       743           brk
  0.01    0.000082           0       245           arch_prctl
  0.01    0.000050           0       134           getdents
  0.00    0.000045           0       245           futex
  0.00    0.000041           0       491           rt_sigaction
  0.00    0.000041           0       246           getrlimit
  0.00    0.000040           0       489       244 ioctl
  0.00    0.000038           0       591           fcntl
  0.00    0.000028           0       204       188 lseek
  0.00    0.000024           0       489           set_robust_list
  0.00    0.000013           0       245           rt_sigprocmask
  0.00    0.000012           0       245           set_tid_address
  0.00    0.000000           0         1           uname
  0.00    0.000000           0       245           fchdir
  0.00    0.000000           0         2         1 statfs
------ ----------- ----------- --------- --------- ----------------
100.00    0.902284                 39085      6803 total

grepのみ

> strace -cf grep -r -i 'the brown dog' .
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 40.00    0.000304           2       134           getdents
 31.71    0.000241           0       533           read
 18.82    0.000143           0       319         6 openat
  4.08    0.000031           4         8           mprotect
  3.29    0.000025           0       199       193 lseek
  2.11    0.000016           0       401           close
  0.00    0.000000           0        38        19 open
  0.00    0.000000           0         6         3 stat
  0.00    0.000000           0       333           fstat
  0.00    0.000000           0        32           mmap
  0.00    0.000000           0         4           munmap
  0.00    0.000000           0         6           brk
  0.00    0.000000           0         2           rt_sigaction
  0.00    0.000000           0         1           rt_sigprocmask
  0.00    0.000000           0       245       244 ioctl
  0.00    0.000000           0         1         1 access
  0.00    0.000000           0         1           execve
  0.00    0.000000           0       471           fcntl
  0.00    0.000000           0         1           getrlimit
  0.00    0.000000           0         1           arch_prctl
  0.00    0.000000           0         1           futex
  0.00    0.000000           0         1           set_tid_address
  0.00    0.000000           0       132           newfstatat
  0.00    0.000000           0         1           set_robust_list
------ ----------- ----------- --------- --------- ----------------
100.00    0.000760                  2871       466 total

答え3

SSD を使用していて、検索時間が無視できる程度であれば、GNU 並列処理を使用できます。

find /path -type f | parallel --gnu --workdir "$PWD" -j 8 '
    grep -i -r 'the brown dog' {} 
'

これは、見つかった内容に応じて最大8つのgrepプロセスを同時に実行しますfind

これはハードドライブに深刻な影響を与えますが、SSDはこれをうまく処理する必要があります。

答え4

これについてもう一つ考慮すべき事項は次のとおりです。

すべてのディレクトリgrepシステム以上の内容を含むファイルを再帰的に参照する必要があります。ファイルなし環境? (たとえば、オープンされたファイルハンドルの数、ほとんどのLinuxディストリビューションのデフォルト値は1024です。)

もしそうなら、探すいくつかのバージョンのため、間違いなく行く方法です。grep砲撃されるパラメータリストが長すぎます。最大オープンファイル処理設定よりも多くのファイルがあるディレクトリに到達するとエラーが発生します。

ただ私の2¢。

関連情報