ファイルシステム全体で文字列が含まれているファイルを見つけるのに効率的なのは、再帰的なgrepとexecステートメントのgrepでの検索のどちらですか。ファイル拡張子またはファイル名と一致する正規表現がわかっている場合は少なくともある程度のフィルタリングを実行できるため、findの方が効率的だと思いますが、-type f
しかわからない場合はどちらが優れていますか? GNU grep 2.6.3; find(GNU findutils)4.4.2
例:
grep -r -i "the brown dog" /
find / -type f -exec grep -i "the brown dog" {} \;
コメント
オプションは必要ありませんでした。 2番目の場合
回答
わからない:
grep -r -i "the brown dog" /*
は本当にあなたが意味したことです。つまり、grepは再帰的に/
内のすべての隠しファイルと隠しファイル(ただし、隠しファイルと隠しファイルの内部を確認します)。
次のことを意味していると仮定します:
grep -r -i "the brown dog" /
注意事項:
- すべての
grep
実装が-r
。そして、そうするものの中で、動作は異なります。ディレクトリツリーをトラバースするときにディレクトリへのシンボリックリンクをたどるものもあります(つまり、seを探してしまう可能性があります)同じファイル内の複数の時間、または無限ループで実行される場合もあります)、そうでないものもあります。デバイスファイル(たとえば、/dev/zero
ではかなり時間がかかります)やパイプまたはバイナリファイルの内部を調べるものもあれば、そうでないものもあります。 -
grep
は、ファイルを検出するとすぐにファイル内の検索を開始するため、効率的です。ただし、ファイルを検索している間は、検索するファイルをさらに検索する必要はありません。ほとんどの場合、おそらく同じです)
あなた:
find / -type f -exec grep -i "the brown dog" {} \;
(-r
ここでは意味がありません)ファイルごとに1つのgrep
を実行しているため、非常に非効率的です。 ;
は、引数を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
は、前の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"
パフォーマンスが大幅に向上する可能性があります。ただし、2番目のgrep
は、最初のgrep
コマンドを満たすのに十分なファイルが見つかった場合にのみ開始されることに注意してください。 -n
オプションをxargs
に追加して、それをより早く実行することができます(そして、grep
呼び出し)。
また、「xargs
出力を端末デバイス以外にリダイレクトする場合は、greps
は出力のバッファリングを開始します。つまり、これらのgrep
の出力はおそらく誤ってインターリーブされます。(GNUやFreeBSDのように利用可能な場合)それを回避するか(非常に長い行(通常は> 4KiB)で問題が発生する可能性があります)、またはそれぞれが出力を別々のファイルに書き込んですべてを連結します最終的に。
ここでは、探している文字列が固定されているため(regexpではありません)、-F
オプションを使用すると違いが生じる可能性があります( grep
の実装は、それを最適化する方法をすでに知っています。
もう1つのことです。 ldが大きな違いを生むのは、「マルチバイトロケールを使用している場合、ロケールをCに修正することです。
find / -type f -print0 | LC_ALL=C xargs -r0 -P2 grep -Hi "the brown dog"
、/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 {} +
コメント
- 私は’誰かが私をリソースに向けたり説明したりできるとは思いません{}と+の意味。 ‘ exec、grep、または使用しているSolarisボックスのmanページに表示されるものは何もありません。’シェルがファイル名を連結してgrepに渡すだけですか?
- @Poldie、’は、 Solarisのマニュアルページの述語
- ああ、そうです。マニュアルページ内を検索しているときに、{div id = “9300b20890”>
が{charをエスケープしていませんでした。あなたのリンクはより良いです。マニュアルページを読むのはひどいです。
回答
grep
呼び出しの*
が重要でない場合は、最初の呼び出しが1つだけであるため、より効率的です。 grep
のインスタンスが開始され、フォークは無料ではありません。ほとんどの場合、*
を使用しても高速になりますが、エッジの場合は高速になります。並べ替えによって逆になる可能性があります。
他のfind
–grep
構造が存在する可能性があります。ファイル。大量のファイルエントリとiノードを一度に読み取ると、回転メディアのパフォーマンスが向上する可能性があります。
ただし、syscall統計を見てみましょう。
find
> 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
コメント
- ファイルシステム全体を検索する規模では、フォークはごくわずかです。 I / Oは削減したいものです。
- OPからのエラーですが、比較は正しくありません。
-r
フラグを削除する必要がありますfindを使用する場合はdivid = “2b5be2b501”>
。発生したopen
の数を比較すると、同じファイルを何度も検索したことがわかります。
-r
は、引数がディレクトリではないことを保証するため、無害である必要があります。複数のopen()
は、各呼び出しでgrep
によって開かれた他のファイル(ライブラリ、ローカリゼーションデータ…)にある可能性が高くなります(私の答えを編集してくれてありがとう)答え
SSDを使用していて、時間を求めている場合無視できる場合は、GNU並列を使用できます。
find /path -type f | parallel --gnu --workdir "$PWD" -j 8 " grep -i -r "the brown dog" {} "
これにより、が見つかりました。
これによりハードディスクドライブが破壊されますが、SSDはかなりうまく対処できるはずです。
回答
これについて考慮すべきもう1つのことは次のとおりです。
grep が再帰的に通過する必要のあるディレクトリにはさらに多くのものが含まれますかシステムの nofile 設定よりもファイルがありますか? (たとえば、開いているファイルハンドルの数、ほとんどのLinuxディストリビューションではデフォルトは1024です)
その場合、 grep 特定のバージョン以降、 find が間違いなく最適な方法です。 / em>は、開いている最大ファイル数よりも多くのファイルがあるディレクトリにヒットすると、引数リストが長すぎるエラーで爆破されます。設定を処理します。
ちょうど私の2 ¢。
コメント
- なぜ
grep
爆弾?少なくともGNUgrepでは、末尾に/
が付いたパスを指定し、-R
it ‘ llは単にディレクトリを反復処理します。 shell は、shell-globsを指定しない限り、’何も拡張しません。したがって、与えられた例(/*
)では、/
の内容のみが重要であり、
、シェルから引数として渡されません。
-exec {} +
フォームはフォークが少なくなるため、-exec {} \;
よりも高速である必要があります。正確に取得するには、-H
(または-h
)をgrep
オプションに追加する必要がある場合があります同等の出力。grep