findがコマンドラインパス引数と一致することがあるのはなぜですか?


9

Linuxでは、

cd /tmp
mkdir foo; cd foo

今、実行しています

find . -name 'foo'

出力はありません。実行中

find /tmp/foo -name 'foo'

/tmp/foo私には意味のない出力を与えます。誰かが理由を説明できますか?


2
それが述べられているように含まれている与えられたパスの内側の場所を見つける 入力./した場合、一致しませんでしたfoo
Costas

@Costas:わかりました。私が理解していないのは、への絶対パスを指定したときに違いが生じた理由findです。
ニューヨーク

@ヨーク特定の状況では、常に正しい動作はありません。検索パスの外barにあるファイルfooを指す名前のシンボリックリンクを想像してください。一致するかどうか。
Hauke Laging

1
同じではありません-彼らは同じディレクトリに二つの異なるハードリンクされています。何も見つかりません。./tmp/foofind /tmp/foo/. -name 'foo'
jimmij

@jimmij:を実行するとfind /tmp/foo -name 'foo'、bashにディレクトリ/tmp/foo「foo」という名前のファイルを見つけるように頼んでいました。ディレクトリ/tmp/fooが空なので、何も返されないはずです。なぜ戻るのかわかりません/tmp/foo。一方、を実行するfind . -name 'foo'と、同じことをbashに尋ねていました。つまり、現在のディレクトリ(たまたま/tmp/foo)で名前が「foo」であるファイルを見つけると、sensを生成するものは何も返されません。
ヨーク

回答:


15

find指定されたディレクトリツリーを走査し、見つかった各ファイルに対して指定された式を評価します。トラバーサルは指定されたパスから始まります。find . -name foo動作方法の概要は次のとおりです。

  • コマンドラインの最初のパス: .
    • ベース名(.)はパターンと一致しますfooか?いいえ、何もしません。
      これ/tmp/fooは、同じディレクトリの別の名前です。しかしfind、それを知りません(そして、それを見つけようとすることは想定されていません)。
    • パスはディレクトリですか?はい、そうです。のエントリを列挙し、エントリ.ごとに走査プロセスを実行します。
      • ディレクトリは空です。再帰的に走査しない.and 以外のエントリは含まれ..findいません。これでジョブは終了しました。

そしてfind /tmp/foo

  • コマンドラインの最初のパス: /tmp/foo
    • ベース名(foo)はパターンと一致しますfooか?はい、条件は一致しています。
      • この条件に関連付けられているアクションはないため、パスを出力するというデフォルトのアクションを実行します。
    • パスはディレクトリですか?はい、そうです。のエントリを列挙し、エントリ/tmp/fooごとに走査プロセスを実行します。
      • ディレクトリは空です。再帰的に走査しない.and 以外のエントリは含まれ..findいません。これでジョブは終了しました。

とてもことが起こる./tmp/foo同じディレクトリにあるが、それは保証するために十分ではありませんfind両方で同じ動作をします。findコマンドは、同じファイルへのパスを区別するための方法を有します。-name述語はそのうちの一つです。find /tmp/foo -name foo開始ディレクトリと、その下にあると呼ばれるファイルに一致しますfoofind . -name .開始ディレクトリのみに一致し.ます(再帰的なトラバーサル中には見つかりません)。


「再帰的に検索しない。と..以外のエントリは含まれていません。」「..」は「再帰的に横断しない」とする。それが正しい場合、「..」の文脈で「再帰的に横断する」とはどういう意味ですか?
Faheem Mitha

@FaheemMithaは「トラバース再帰的にしない」の両方に適用されます...。(場合findトラバース.再帰的に、それは何度も何度も何度もディレクトリを通過終わると...う)...、彼らはディレクトリエントリとして表示され、ちょうど特別な表記ではありません。
Gilles 'SO-悪をやめる'

5

テストが適用される前に、コマンドライン引数の正規化はありません。したがって、結果は使用するパスによって異なります(シンボリックリンクが含まれている場合)。

cd /tmp
mkdir foo
ln -s foo bar
find /tmp/foo -name foo
find /tmp/bar -name foo

「あなたの場合」では、両方の呼び出しで同じ結果が得られ、混乱を招く可能性があります。-mindepth 1開始点を無視したい場合に使用できます(POSIX以外の場合もあります)。


-mindepth 1動作します。しかし、私はまだ理由find . -name 'foo'を理解しておらず、find /tmp/foo -name 'foo'動作が異なります。
ニューヨーク

2

(gnu)findは、コマンドライン引数との比較を開始し、そこからディレクトリ構造のより深いところに降順であるため、コマンドに提供されたパス内で見つかった一致を表示します(したがって、-maxdepth 0テストをベースレベルまたはコマンドライン引数のみに限定しますが、説明-mindepth 1に従ってコマンドライン引数をスキップしman findます)。これが、find /tmp/foo -name 'foo'ディレクトリ自体が空の場合でも1つの一致が生成される理由です。

find . -name 'foo'一方、.(ドット)は同じiノードへのハードリンクのように機能する特別なファイルであるため、結果は生成されません/tmp/foo-シンボリックリンクや対象となる式ではなく、別の(特別な)ファイル名のようですシェルによるパス名展開。したがって、与えられた例のコマンドライン引数にfindによって適用された最初のテストは、.実際にはで定義された名前パターンと一致しないため、一致は表示されません-name 'foo'。どちらも行わない/tmp/foo/.ためのテストので-nameパターンはパスのみ(参照のベース名で実行されman find、ここで再び).

この動作はユーザーの観点からは予期されないか、直感的に表示される場合があります(もちろん、最初は混乱していました)が、バグを構成するものではありませんが、(のmanおよびinfoページで説明されているロジックと機能に対応していますgnu)見つける。


0

Gillesの回答にコメントしてみましたが、長すぎてコメントに収まりませんでした。このため、私はそれを自分の質問への回答として掲載します。

Gillesの説明(およびShevekの説明も)は明確で意味があります。ここで重要なのはfind、指定されたパス内のファイルのファイル名を(再帰的に)一致させるだけでなく、指定されたパス自体のベース名も一致させようとすることです。

一方、これがfindバグではなく、動作する方法であると考えられる証拠はありますか?それがための結果の矛盾せない場合は私の意見では、それが良いだろうfind .とのfind ABSOLUTE-PATH矛盾が常に混乱して、開発者は「何が間違っていた」把握しようと多くの時間を無駄にする可能性があるため。私の場合、スクリプトを作成していて、パスは変数から取得されました。私のスクリプトが適切に機能するために、私が考えることができることは、を書くことfind $path/. -name 'pattern'です。

最後に、続行する前にfind常にを.現在のディレクトリに置き換えることで、の一貫した結果を得ることができると思います。


-1

foo相対検索を開始したディレクトリに名前の付いたオブジェクトはありません。

あなたはgfindそれ/tmp/fooが絶対名を開始ディレクトリとして使用するときにそれが報告するときバグがあると仮定することで正しいです。

Gfind標準からのさまざまな偏差がありますが、別のものを見つけたようです。より標準に準拠したソリューションが必要な場合は、それsfindがの一部であることをお勧めしschilytoolsます。

-nameディレクトリ検索結果に適用されます。言及した2つのケースのいずれもfooreaddir()操作からディレクトリエントリを返しません。


これもバグだと思います。以下に出力を示しfind --versionます。find(GNU findutils)4.4.2 Copyright(C)2007 Free Software Foundation、Inc.ライセンスGPLv3 +:GNU GPLバージョン3以降< gnu.org/licenses/gpl.html >
York

さて、私はあなたのコマンド例をfind(POSIX認定済み)で確認 gfindしましたsfind。この問題は、を使用した場合にのみ発生しますgfind。Linuxでは、gfindはそのネイティブ名ではなく、という名前でインストールされfindます。
schily

3
find /tmp/foo -name foo出力するのは正しいです/tmp/foo。(Cc @York)これは、OpenBSD find、GNU find、BusyBox find、Solaris find、およびその他のPOSIX準拠の動作ですfind(「プライマリファイル名は、検査対象のファイル名のベース名がパターン(...)と一致する場合にtrueと評価されます)—ファイル名がパスオペランドとして渡されるもので、readdir呼び出しは含まれません)。
Gilles 'SO-邪悪なことをやめなさい'
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.