"-prune"にもかかわらず、 "find"がまだ.gvfsにアクセスしようとし、それを出力に含めようとしているのはなぜですか?

辞書:これは一般的な問題(すべてのフォルダに当てはまると仮定)から特定の極端なケースに発展しました。
私のように気になる方もいらっしゃるようで質問を削除せずに書き直すことにしました。


自分のホームフォルダに直接含まれているすべてのアイテム(ドットファイルとフォルダを除く)を一覧表示したいとします。 IMHO 次の find コマンドがこれを行う必要があります。.hidden(ファイルを使用すると「隠しプロジェクト」が異なる場合があるため、「ドットプロジェクト」と明示的に書きました):

find $HOME/ -mindepth 1 -maxdepth 1 -path "$HOME/.*" -prune -o -print

-mindepth 1$HOME自体を含めず、1つの-maxdepth 1フォルダレベルに制限し、-path "$HOME/.*" -pruneホームフォルダからドットで始まる項目を除いて、-o -printデフォルトマニュアルページ

今まではそんなに良くなった。それは一種の働きます(無許可のドットフォルダがあるが)。しかし、$HOME/.gvfsまったくアクセスできないはずですが、次の理由で窒息し始めます-path ... -prune

/home/user/file a
/home/user/folder b
...
find: '/home/user/.gvfs': Permission denied
/home/user/.gvfs
...
/home/user/file z

-permatを使っfind2> /dev/null解決できるということはわかるが、私が本当に驚いたことは、/home/user/.gvfsすでにリストに含まれています。(他のすべてのポイントアイテムは除外されますが)! ! !
私は、観察力が不足している一部の人々がエラーを振り返り、進み続けようと努力2> /dev/nullすると確信しています。 ...もし1> /dev/null100行の長いリストは、コマンドを使用する前にaddなどのメソッドを使用して明示的にエラーを確認する必要があるため、完全にエラーを認識します。


ディレクトリ/ツリーは実際に無視されますか?

なぜこれが防止されるのか、少なくとも防止されるべきであるにもかかわらず、アクセスを試みるのはなぜですかfind?たとえば、マニュアルページから:/home/user/.gvfs-maxdepth 1-prune

'-prune'操作(のみさらなる落下防止[...])

私のシステムにインストールされている以前のマニュアルページにも-path次のように記載されています。

到着完全なディレクトリツリーを無視、ツリー内のすべてのファイルを確認するのではなく、-pruneを使用してください。

「無視された」ディレクトリ自体の危険なリストです!

すべてが実際に無視される場合、/home/user/.*私の質問の2番目の部分は必要ないかもしれません。これは内部エラーによるものです。
なぜ/home/user/.gvfsまだリストにあり、どのように防ぐことができますか?-user/-permおよび2> /dev/nullすべてのfindコマンド(少なくとも作業-prune)を操作する必要がない方法はありますか?

今後の活用 - >効率性?

実際に無視されている-prune(または少なくとも無視される-path ... -prune)ものは何ですか?

(ほとんど)すべてのファイルがまだスキャンされている場合は、この複雑なオプションの使用を放棄し、代わりにorを-prune使用します。特にエラーが発生しやすいので、さらにそうです。 !-not-prune

ベストアンサー1

そうだ間違いGNU実装では、findトリガーは(ファイルのメタデータを取得する)システムコールであるlstat()ようです。fstatat()EACCESS許可が拒否されました)ファイルに.gvfs

これは通常、ファイルがFUSEベースのファイルシステムのマウントポイントであるため、Linuxで発生しますが、-o allow-otherこのオプションは使用されていません。これは、アクセスできない領域を指すシンボリックリンクがある場合でも発生する可能性がfind -Lあります。find -follow

ここで私が見つけたのは、-pruneこれらのファイルに対して返されることです。間違った-prune文書化された(およびPOSIX必須)常に返されるように、これは明らかにバグです。本物

バグが修正されるまで、回避策として次のよう-pruneに置き換えることができます'(' -prune -o -true ')'。 (これは-trueGNU拡張です。移植可能な拡張も可能です! -name ''が、移植可能な拡張は正しいことを保証します。'(' -prune -o ! -prune ')'

今、コード自体にいくつかの問題があります。存在する:

find $HOME/ -mindepth 1 -maxdepth 1 -path "$HOME/.*" -prune -o -print
  • ほとんどのBourne様シェルでは$HOME/これを引用する必要があります。それ以外の場合、$HOME拡張は分割+グローブの影響を受けます。これを書くこともできます~/
  • -prunefindディレクトリに入らないように言いました。最上位(深さ0)ディレクトリを除くすべてのディレクトリに降りるmaxdepth 1のをやめるので、ここでは重複します。find$HOME/
  • -pathパターンを採用してください。これは、コンテンツが$HOMEパターンとして処理されることを意味します。$HOMEたとえば、あなたが裏面/home/[112] meでは一致しますが、-path '/home/[112] me/.*'一致しません。また、ここではフルパスを一致させる必要はなく、代わりにファイル名を一致させることもできます。/home/2 me/.foo/home/[112] me/.foo-name '.*'
  • *GNUのみfind一致数値したがって、次.*から始まるファイル名と一致します。. そしてまた、有効な文字を形成する一連のバイトで構成されます。したがって、C各バイトシーケンスが有効な文字(ロケールなど)を形成するロケールの隠しファイルを一致させるためにのみ使用できます。

したがって、ここで要点がフルパスでHOMEディレクトリに隠されていないファイルを一覧表示することである場合は、次のことができます。

LC_ALL=C find ~/ -mindepth 1 -maxdepth 1 ! -name '.*'

これはまた、GNUfindエラーを防止します。

または標準の等価項目(/./パスにaを追加しても):

LC_ALL=C find ~/. ! -name . -prune ! -name '.*'

find(ここではファイルでGNUエラーが発生します。いいえ始めることは.不可能ですlstat()が、上記のエラーの説明に示すように、lstat()不可能なファイルが報告されるかどうかは実装ごとに大きく異なります。

ここでは以下を使用しますzsh

print -rC1 ~/*(ND)

または、次のようにソートしたくない場合find

print -rC1 ~/*(NDoN)

おすすめ記事