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

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

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

この行動の正しい説明は何ですか?

答え1

(私はfindこれがGNUであると仮定しています)

のみ使用

find filename

会議filenameディレクトリの場合は内部名のみを返し、現在のディレクトリに名前がない場合はエラーのみを返すため、より高速です。filenameこれは非常に高速な操作に似ていますls filename(ただし、filenameディレクトリの場合は再帰的です)。

対照的に、

find | grep filename

findリストを作成できます。みんなこれにより、現在のディレクトリと次のディレクトリの名前がgrepフィルタリングされます。これは明らかにはるかに遅い作業です。

私が推測するもの実際にもともと目的はこれでした。

find . -type f -name 'filename'

これにより、現在のディレクトリまたは次のディレクトリでfilename一般ファイルの名前が検索されます。

これは高速または非常に高速ですが、回避策はfind | grep filename方法と同様に、見つかった各名前のフルパスを一致させることです。grepfilename-path '*filename*'find


これらの混乱は、find物事がどのように機能するかについての誤解から来ています。

このユーティリティには一部が必要です。このパスの下のすべての名前を返します。

それからあなたはできます限界ファイル名、パス、タイムスタンプ、ファイルサイズ、ファイル形式などで機能できるさまざまなテストから返された名前を使用してください。

言うと

find a b c

find3つのパスと利用可能な各名前を一覧表示aするようbに求められますc。これが現在ディレクトリにある一般ファイルの名前である場合は、その名前が返されます。そのうちの1つがディレクトリ名の場合は、そのディレクトリ内の他のすべての名前と一緒に返されます。

私がするとき

find . -type f -name 'filename'

.これにより、現在のディレクトリ()以下のすべての名前のリストが生成されます。-type f次に、名前の拡張子filename-name 'filename'。たとえば、文字列はfilenameファイル名のワイルドカードパターンです*.txt(引用符だけを覚えておいてください)。

例:

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

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

ただし、実際にはパス内のすべての名前を返します.profile(このファイルの名前は1つだけです)。

その後、cd1つのレベルに上がって再試行します。

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

findこれで、コマンドは名前付きパスを見つけることができません.profile

ただし、現在のディレクトリを表示するように指示した場合返される名前は次のように制限されます。.profile、そこからも探します。

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

答え2

非技術的な説明:群衆の中でJackを見つけることは、Jackを除くすべての人を除いて、群衆の中ですべての人を見つけるよりも速いです。

答え3

まだ問題を理解していませんが、より多くの洞察を提供できます。

Kusalanandaのように、find | grep私のシステムでの呼び出しは確かに高速ですが、これはあまり意味がありません。最初は、ある種のバッファリング問題があると仮定しました。コンソールに書き込むと、次のファイル名を読み取るための次のシステムコールが遅くなりました。パイプへの書き込みは非常に高速です。 32バイト書き込みの場合でも約40MiB / sです(かなり遅いシステムでは1MiBブロックサイズの場合は300MiB / s)。したがって、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

findgrepしかし、次のように高速かもしれません。

findこの愚かさはname他のテストに拡張されていないことがわかりました。代わりに正規表現を使用すると問題が消えます。

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

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

これはバグだと見ることができると思います。バグレポートを提出する意思がある人はいますか?私のバージョンはfind(GNU findutils)4.6.0です。

答え4

/john/paul/george/ringo/beatles ファイルが存在し、検索中のファイルの名前が「stones」であるとします。

find / stones

find は "beatles" を "stones" と比較し、一致しない場合は "s" と "b" を削除します。

find / | grep stones

この場合、 find は "/john/paul/george/ringo/beatles" を grep に渡し、grep が一致することを確認する前にパス全体をナビゲートする必要があります。

したがって、grepはより多くのタスクを実行するので、時間がかかります。

関連情報