なぜコマンドは「find | grep 'filename'”は、「find 'filename'」よりもはるかに遅いですか?


10

私は両方のコマンドを試しましたが、コマンド find | grep 'filename' は単純なfind 'filename' コマンドよりも何倍も遅いです。

この動作の正しい説明は何でしょうか?


2
すべてのファイルをfindでリストし、データをgrepに渡して処理します。findを独自に使用すると、リストされたすべてのファイルをgrepに渡して出力を解析する手順がありません。したがって、これはより速くなります。
Raman Sailopal 2017年

どういう意味で遅い?コマンドの完了には別の時間がかかりますか?
クサラナンダ

1
これをローカルで再現することはできません。どちらかとtime find "$HOME" -name '.profile'言えば、よりも長い時間を報告しtime find "$HOME" | grep -F '.profile'ます。(17秒vs 12秒)。
クサラナンダ

2
@JenniferAnderson私は繰り返し両方を実行しました。17秒と12秒は平均です。そして、はい、grepバリエーションはfind結果のどこにでも一致しますfind -nameが、との一致は完全に一致するだけです(この場合)。
クサラナンダ

2
はい、find filename 高速になります。私はこれがタイプミスであり、OPが意味するものだと思っていましたfind -name filename。を使用すると、検査find filenameのみfilenameが行われます(それ以外は行われません)。
クサラナンダ

回答:


11

findここではGNUを想定しています)

ただ使う

find filename

、、filenameまたはfilenameディレクトリの場合は内部の名前、現在のディレクトリにその名前が存在しない場合はエラーを返すため、迅速です。これはls filenamefilenameディレクトリの場合は再帰的)と同様の非常に高速な操作です。

対照的に、

find | grep filename

現在のディレクトリ以下からすべての名前のfindリストを生成できるようになり、フィルタリングされます。これは明らかにはるかに遅い操作になります。grep

私がいたものと仮定しています実際には意図していました

find . -type f -name 'filename'

これはfilename、現在のディレクトリまたはその下のどこかにある通常のファイルの名前として検索されます。

これはと同じくらい高速(または比較的高速)find | grep filenameですが、grep解決策は、の場合とfilename同様に、見つかった各名前の完全パスと照合さ-path '*filename*'findます。


混乱は、動作の誤解から生じますfind

ユーティリティはいくつかのパスを取り、これらのパスの下にあるすべての名前を返します。

次に、ファイル名、パス、タイムスタンプ、ファイルサイズ、ファイルタイプなどに作用するさまざまなテストを使用して、返される名前を制限できます。

あなたが言う時

find a b c

あなたが求めるfind3回のパスで利用可能なすべての名前を一覧表示するabc。これらが現在のディレクトリにある通常のファイルの名前である場合、これらが返されます。それらのいずれかがたまたまディレクトリの名前である場合、そのディレクトリ内のすべての追加の名前とともに返されます。

私がする時

find . -type f -name 'filename'

これにより、現在のディレクトリ(.)以下のすべての名前のリストが生成されます。次に、名前を通常のファイルの名前に制限します。つまり、ディレクトリなどではありません-type f。そして、一致する名前にさらに制限がfilename使用しては-name 'filename'。文字列filenameは、次のようにファイル名の展開パターンにすることができます*.txt(引用することを忘れないでください!)。

例:

以下.profileは、ホームディレクトリで呼び出されたファイルを「見つける」ようです。

$ pwd
/home/kk
$ find .profile
.profile

しかし、実際には、パスにあるすべての名前を返す.profileだけです(名前は1つだけで、それはこのファイルのものです)。

次にcd、1レベル上げて、もう一度やり直します。

$ cd ..
$ pwd
/home
$ find .profile
find: .profile: No such file or directory

findコマンドは、今と呼ばれる任意のパスを見つけることができません.profile

ただし、現在のディレクトリを調べて、返される名前をのみに制限する.profileと、そこからも検索されます。

$ pwd
/home
$ find . -name '.profile'
./kk/.profile

1
find filenameのみ返すfilename場合filename型のなかったディレクトリ(またはディレクトリ型であったが、いずれかのエントリ自体がありませんでした)
ステファンChazelas

2

非技術的な説明:群集の中でジャックを探すことは、群集の中のすべての人を探すことよりも速く、ジャック以外のすべてを考慮から除外します。


問題は、OPがジャックが群衆の中で唯一の人物であることを期待していることです。もしそうなら、彼らは幸運です。 という名前のファイルであるか、ディレクトリの場合はディレクトリ内のすべての名前find jackがリストされjackますjack。それはどのようにfind機能するかについての誤解です。
クサラナンダ

1

私はまだ問題を理解していませんが、いくつかの洞察を提供できます。

クサラナンダの場合と同様find | grepに、私のシステムでは呼び出しは明らかに高速であり、あまり意味がありません。最初に、ある種のバッファリングの問題を想定しました。コンソールへの書き込みにより、次のファイル名を読み取るための次のシステムコールまでの時間が遅くなります。パイプへの書き込みは非常に高速です:32バイトの書き込みでも約40 MiB /秒(やや遅いシステムでは、1 MiBのブロックサイズで300 MiB /秒)。したがってfind、パイプ(またはファイル)に書き込むときにファイルシステムからより速く読み取ることができるため、ファイルパスの読み取りとコンソールへの書き込みの2つの操作を並行して実行できる(find単一のスレッドプロセスだけでは実行できない)と想定しました。

それはのfindせい

2つの呼び出しの比較

:> time find "$HOME"/ -name '*.txt' >/dev/null

real    0m0.965s
user    0m0.532s
sys     0m0.423s

そして

:> time find "$HOME"/ >/dev/null

real    0m0.653s
user    0m0.242s
sys     0m0.405s

find信じられないほど愚かなことをしていることを示しています(それが何であれ)。それは実行するのにかなり無能であることがわかりました-name '*.txt'

入力/出力比に依存する可能性があります

find -name書くことがほとんどないのなら、それが勝つと思うかもしれません。しかし、それだけではもっと恥ずかしいことになりfindます。200Kのファイル(13Mのパイプデータ)に対して何も書き込むものがなくても、次の場合は失われますgrep

time find /usr -name lwevhewoivhol

find速さとすることができgrep、しかし、

これは、ことが判明したfindとの愚かさは、name他のテストには拡張されません。代わりに正規表現を使用してください。問題はなくなりました。

:> time find "$HOME"/ -regex '\.txt$' >/dev/null     

real    0m0.679s
user    0m0.264s
sys     0m0.410s

これはバグと考えることができます。バグレポートを提出してくれる人はいますか?私のバージョンはfind(GNU findutils)4.6.0です


あなたのタイミングはどのくらい再現可能ですか?-name最初にテストを行った場合は、ディレクトリの内容がキャッシュされていないため、速度が低下している可能性があります。(テストを行ったところ-name-regexほぼ同じ時間がかかっていることがわかりました。少なくともキャッシュ効果が考慮に入れられた後です。もちろん、バージョンが異なるだけかもしれませんfind...)
psmears

@psmearsもちろん、私はこれらのテストを数回行っています。キャッシングの問題は、最初の回答の前の質問へのコメントでも言及されています。私のfindバージョンはfind(GNU findutils)4.6.0
Hauke Laging

追加-name '*.txt'が遅くなるのはなぜ驚くのfindですか?各ファイル名をテストして、余分な作業を行う必要があります。
Barmar

@Barmar Oneでは、この余分な作業を非常に高速に実行できます。一方、この余分な作業は他の作業を節約します。findより少ないデータを書き込む必要があります。そして、パイプへの書き込みははるかに遅い操作です。
Hauke Laging 2017年

ディスクへの書き込みは非常に遅く、パイプへの書き込みはそれほど悪くありません。カーネルバッファーにコピーするだけです。最初のテストでは、/dev/null何らかの方法でより多くの書き込みを行うと、システム時間の使用量が減少したことに注意してください。
Barmar

0

通知:私はあなたが意味していると仮定しますfind . -name filename(そうでない場合は、別のものを探しています。find filename実際にはfilenameと呼ばれるパスを調べます。ファイルにはほとんどファイルが含まれていない可能性があるため、すぐに終了します)。


5000個のファイルを保持するディレクトリがあるとします。ほとんどのファイルシステムでは、これらのファイルは実際にはツリー構造に格納されているため、特定のファイルをすばやく見つけることができます。

あなたが尋ねるときにfind、名前だけチェックが必要ですファイルを見つけるために、findだろう頼むためにそのマスストレージから非常にいくつかのページを読み込みます基礎となるファイルシステムに、ファイル、およびそのファイルだけ。したがって、ファイルシステムがその価値がある場合、この操作は、ツリー全体を走査してすべてのエントリを取得するよりもはるかに速く実行されます。

あなたがプレーンを要求するときfind、それがまさにあなたがしていることです、あなたは読んでツリー全体を行き来します。すべて。シングル。エントリ。大きなディレクトリの場合、これは問題になる可能性があります(ディスクに大量のファイルを保存する必要があるいくつかのソフトウェアが2つまたは3つのコンポーネントの「ディレクトリツリー」を作成する理由です。ファイル)。


-2

/ john / paul / george / ringo / beatlesファイルが存在し、検索しているファイルが「ストーン」と呼ばれていると仮定しましょう

find / stones

findは「ビートルズ」と「ストーンズ」を比較し、「s」と「b」が一致しない場合はドロップします。

find / | grep stones

この場合、findは '/ john / paul / george / ringo / beatles'をgrepに渡し、grepはパスが一致するかどうかを判断する前にパス全体をたどる必要があります。

したがって、grepははるかに多くの作業を行っているため、時間がかかります


1
やってみましたか?
Hauke Laging 2017年

3
文字列比較のコスト(非常にシンプルで安価)は、ディレクトリルックアップのIO(またはキャッシュされている場合はsyscall)コストによって完全に小さくなります。
マット

grepは文字列比較ではありません。正規表現の比較です。つまり、一致が見つかるか、末尾に到達するまで、文字列全体を調べなければなりません。ディレクトリ検索は、何があっても同じです。
妄想的な

@Paranoid Hm、あなたが話しているfindのバージョンは何ですか?どうやら、私がdebianで慣れているfindのようなものではないようです。
パイプ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.