ファイルシステム全体で文字列を含むファイルを見つけるために、再帰的な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つの引数のみを許可するコマンドでのみ使用できます。そして、ここではgrep
1つのファイルしか探していないので、ファイル名は印刷されないので、一致するものがどこにあるのかわかりません。
デバイスファイル、パイプ、シンボリックリンクを見ず、シンボリックリンクに従わないが、それでも/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
アクセスすると、ディスクヘッドが継続的に移動し、ディスクスループットが低下します。これはgrep
RAID設定(他のディスクにアクセスfind
できるgrep
)またはSSDに良い影響を与える可能性があります。
RAID設定で複数実行同時に grep
電話をかけると状況が改善する可能性があります。まだ3つのディスクRAID1ストレージでGNUツールを使用しています。
find / -type f -print0 | xargs -r0 -P2 grep -Hi 'the brown dog'
パフォーマンスが大幅に向上する可能性があります。ただし、grep
最初のコマンドを入力するのに十分なファイルが見つかるまで、2番目のgrep
コマンドは開始されません。このタスクがより速く実行されるように(および呼び出しごとに少ないファイル数を渡すように)-n
オプションを追加できます。xargs
grep
xargs
また、出力をターミナルデバイス以外のものにリダイレクトすると、greps
sは出力バッファリングを開始します。これは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¢。