私は両方のコマンドを試しましたが、コマンドfind | grep 'filename'
は単純なfind 'filename'
コマンドよりも何倍も遅いです。
この動作の正しい説明は何でしょうか?
(GNU find
hereと仮定しています)
ただ使う
find filename
wouldは、filename
、またはディレクトリの場合はfilename
内の名前を返し、その名前が現在のディレクトリに存在しない場合はエラーを返すため、迅速です。これは、ls filename
に似た非常に高速な操作です(ただし、filename
がディレクトリの場合は再帰的です)。
対照的に、
find | grep filename
find
がallの名前のリストを現在のディレクトリ以下から生成できるようにし、grep
がフィルタリングします。これは明らかにはるかに遅い操作になります。
実際にが意図したものは
find . -type f -name 'filename'
これは、現在のディレクトリまたはその下のどこかにある通常のファイルの名前としてfilename
を探します。
これはfind | grep filename
と同じくらい高速(または同等に高速)ですが、grep
ソリューションは、-path '*filename*'
がfilename
で行うのと同様に、find
を、見つかった各名前の完全パスと照合します。
混乱は、find
の機能に関する誤解から生じます。
ユーティリティはいくつかのpathsを受け取り、これらのパスの下にあるすべての名前を返します。
次に、ファイル名、パス、タイムスタンプ、ファイルサイズ、ファイルタイプなどに作用するさまざまなテストを使用して、返される名前をrestrictできます。
あなたが言う時
find a b c
find
に、a
、b
、c
の3つのパスで使用できるすべての名前をリストするように要求します。これらがたまたま現在のディレクトリにある通常のファイルの名前である場合、これらは返されます。それらのいずれかがたまたまディレクトリの名前である場合、そのディレクトリ内のすべての追加の名前とともに返されます。
私がする時
find . -type f -name 'filename'
これにより、現在のディレクトリ(.
)以下のすべての名前のリストが生成されます。次に、-type f
を使用して、ディレクトリなどではなく、通常のファイルの名前に制限します。次に、-name 'filename'
を使用して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
技術的でない説明:群集の中でジャックを探すことは、群集の中の全員を探すことよりも速く、ジャック以外のすべてを考慮から除外します。
私はまだ問題を理解していませんが、もう少し洞察を提供できます。
クサラナンダの場合と同様に、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
が勝つと思うかもしれません。しかし、istはfind
をより恥ずかしく思うだけです。 grep
の200Kファイル(13Mのパイプデータ)に対して書き込むものが何もない場合でも失われます。
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です。
通知:私はあなたがfind . -name filename
(そうでなければ、別のものを探しています; find filename
は実際にはfilenameと呼ばれるパスを調べます。これにはほとんどファイルが含まれていない可能性があるため、非常に迅速に終了します)。
5000個のファイルを保持するディレクトリがあるとします。ほとんどのファイルシステムでは、これらのファイルは実際には tree構造 に格納されているため、特定のファイルをすばやく見つけることができます。
したがって、find
に名前の確認のみが必要なファイルを見つけるように依頼すると、find
はaskに対してthatファイルを検索し、そのファイルのみを検索します、基盤となるファイルシステムへ。これは、マスストレージから非常に少ないページを読み取ります。したがって、ファイルシステムがその価値がある場合、この操作はすべてのエントリを取得するためにツリー全体をトラバースするよりもはるかに高速に実行されます。
単純なfind
を要求すると、それが実際に行うことですが、ツリー全体をトラバースして読み取ります。すべて。シングル。エントリ。大きなディレクトリの場合、これが問題になる可能性があります(ディスクに多くのファイルを格納する必要があるいくつかのソフトウェアが2つまたは3つのコンポーネントの「ディレクトリツリー」を作成するのはまさにそのためです。ファイル)。