ファイルシステム全体で文字列が含まれているファイルを見つけるのに効率的なのは、再帰的な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" {} \;

コメント

  • 数学/コンピュータサイエンス/アルゴリズムの効率に関する意見’ベース。
  • これを確認してください。再帰的ではありませんが、どちらが優れているかを理解できます。 unix.stackexchange.com/questions/47983/ …
  • @AvinashRaj he ‘は意見を求めていません。彼は’ ‘どちらがより効率的で、より高速であるかを尋ねています。 “より良い”ではありません。これは完全に答えられる質問であり、これら2つのプログラムがどのように機能するか、および検索するために正確に何を与えるかによって、1つの具体的な答えがあります。
  • -exec {} +フォームはフォークが少なくなるため、-exec {} \;よりも高速である必要があります。正確に取得するには、-H(または-h)をgrepオプションに追加する必要がある場合があります同等の出力。
  • おそらく’ grep

オプションは必要ありませんでした。 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呼び出しが最初のバッチ内を検索している間、さらにファイルを検索し続けます。しかし、それは利点かもしれないし、そうでないかもしれません。たとえば、回転式ハードドライブにデータが保存されている場合、findgrepがディスクの異なる場所に保存されているデータにアクセスすると、ディスクの速度が低下します。ディスクヘッドを絶えず動かすことによるスループット。 RAIDセットアップ(findgrepが異なるディスクにアクセスする可能性がある場合)または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をエスケープしていませんでした。あなたのリンクはより良いです。マニュアルページを読むのはひどいです。

  • 3枚のディスクを備えたRAID1?奇妙なことに…
  • @tink、はいRAID1は2つ以上のディスク上にあります。 2つのディスクと比較して3つのディスクを使用すると、冗長性と読み取りパフォーマンスが向上しますが、書き込みパフォーマンスはほぼ同じです。 2つではなく3つのディスクを使用すると、エラーを修正することもできます。たとえば、コピーの1つを少し反転すると、’すべてをチェックすることで、どちらが正しいかを判断できます。 2つのディスクで3つのコピーがある場合、’実際にはわかりません。
  • 回答

    grep呼び出しの*が重要でない場合は、最初の呼び出しが1つだけであるため、より効率的です。 grepのインスタンスが開始され、フォークは無料ではありません。ほとんどの場合、*を使用しても高速になりますが、エッジの場合は高速になります。並べ替えによって逆になる可能性があります。

    他のfindgrep構造が存在する可能性があります。ファイル。大量のファイルエントリと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の数を比較すると、同じファイルを何度も検索したことがわかります。

  • @qwertzguy、いいえ、-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を指定しない限り、’何も拡張しません。したがって、与えられた例(/*)では、/の内容のみが重要であり、

    、シェルから引数として渡されません。

  • OPが再帰的に検索することを求めていたことを考えると(例:” grep -r -i ‘茶色の犬’ / * “)、私は見たGNU ‘ s grep (少なくともバージョン2.9)は:” -bash:/ bin /で爆撃しますgrep:引数リストが長すぎます” 140,000を超えるサブディレクトリがあるディレクトリで使用されたOPの正確な検索を使用しています。
  • コメントを残す

    メールアドレスが公開されることはありません。 * が付いている欄は必須項目です