POSIX検索を特定の深さに制限しますか?


15

最近、POSIX仕様にfind-maxdepthプライマリが含まれていないことに気付きました。

それに不慣れな人にとって、-maxdepthプライマリの目的は、いくつの深findさのレベルが下がるかを制限することです。 -maxdepth 0で結果だけで処理されているコマンドライン引数。-maxdepth 1コマンドライン引数などで直接結果のみを処理します。

-maxdepthPOSIXで指定されたオプションとツールのみを使用して、非POSIX プライマリと同等の動作を取得するにはどうすればよいですか?

(注:もちろん、第1オペランドとして-maxdepth 0使用するだけで同等の機能を取得できますが、-prune他の深さまでは拡張されません。)


@StevenPenny、FreeBSDのは-depth -2-depth 1...アプローチは、GNUのより良いとして見ることができる-maxdepth/-mindepth
ステファンChazelas

いずれにしても@StéphaneChazelas-POSIX findにはどちらか一方が必要です。それ以外の場合は機能しません
スティーブンペニー

1
少なくとも-maxdepth/ -mindepthには、合理的な代替手段があります(-pathPOSIXに最近追加されたことに注意してください)。-timexyor -mtime -3m(または-mmin -3)の代替ははるかに面倒です。-execdir/のようなものに-deleteは、信頼できる代替手段がありません。
ステファンシャゼル16

2
@StevenPennyは、でチケットログインして自由に感じるaustingroupbugs.netを、それを追加することを要求します。強力な正当化があったときに、スポンサーを必要とせずに物事が追加されるのを見てきました。おそらくより良いアクションコースは、多くの実装が最初にそれを追加するので、POSIXは、一般的にあまり議論のない既存のものを指定するだけです。
ステファンシャゼル16

@StéphaneChazelasの場合、ファイルに直接名前を付けるだけでしたが、ありがとうございます。これが再び発生した場合、チケットを提出することがあります
スティーブンペニー

回答:


7

を使用-pathして、指定された深さに一致させ、そこをプルーニングできます。例えば

find . -path '*/*/*' -prune -o -type d -print

MAXDEPTH 1、あろう*マッチ.*/*マッチ./dir1、及び*/*/*マッチ./dir1/dir2プルーニングされます。絶対開始ディレクトリを使用する場合は、先頭/-pathも追加する必要があります。


うーん、トリッキー。/*パターンの最後から1つのレイヤーを削除し、-o演算子を取り出して同じ結果を得ることができませんでしたか?
ワイルドカード

いいえ、同様に*一致するため、悲しいことに、/ディレクトリa/b/c/d/eが収まり-path */*ます。
meuh

しかし、... に適用されるため、到達a/b/c/d/eすることはありません-prunea/b
ワイルドカード

1
申し訳ありませんが、私はそれを読み違える-pruneと、-o削除されました。あなた-pruneが問題を保持する場合は*/*、maxdepthを超えるレベルでは何も一致しないということです、例えばsingle directory a
-meuh

11

@meuhのアプローチは非効率的です。なぜなら、彼の-maxdepth 1アプローチfindではレベル1のディレクトリの内容を読み取って、それ以外の場合は後で無視できるからです。一部のディレクトリ名に、ユーザーのロケールで有効な文字を形成しないバイトシーケンスが含まれている場合(別の文字エンコーディングのファイル名findなどfind)、一部の実装(GNUを含む)でも正常に動作しません。

find . \( -name . -o -prune \) -extra-conditions-and-actions

GNU -maxdepth 1(またはFreeBSD -depth -2)を実装する、より標準的な方法です。

ただし、一般的には、考慮したくない(深さ0)ために-depth 1-mindepth 1 -maxdepth 1)が必要.であり、さらに簡単です:

find . ! -name . -prune -extra-conditions-and-actions

の場合-maxdepth 2、次のようになります。

find . \( ! -path './*/*' -o -prune \) -extra-conditions-and-actions

そして、それはあなたが無効なキャラクターの問題で実行する場所です。

たとえば、あなたはというディレクトリがある場合Stéphaneが、é西ヨーロッパとアメリカで最も一般的なアップは、その後0xe9バイトがないことを、半ば2000年代まであったように、ISO8859-1(別名latin1の)文字セット(0xe9バイト)でエンコードされているがUTF-8の有効な文字。だから、UTF-8ロケールでは、*(一部でワイルドカードfindの実装が)一致しませんStéphaneよう*0以上で、文字と文字が0xe9ではありません。

$ locale charmap
UTF-8
$ find . -maxdepth 2
.
./St?phane
./St?phane/Chazelas
./Stéphane
./Stéphane/Chazelas
./John
./John/Smith
$ find . \( ! -path './*/*' -o -prune \)
.
./St?phane
./St?phane/Chazelas
./St?phane/Chazelas/age
./St?phane/Chazelas/gender
./St?phane/Chazelas/address
./Stéphane
./Stéphane/Chazelas
./John
./John/Smith

My find(出力が端末に送信されるとき)は、?上記のように無効な0xe9バイトを表示します。d でSt<0xe9>phane/Chazelasはないことがわかりpruneます。

次の方法で回避できます。

LC_ALL=C find . \( ! -path './*/*' -o -prune \) -extra-conditions-and-actions

ただし、それはすべてのロケール設定findとそれが実行するアプリケーションに影響することに注意してください(-exec述語経由など)。

$ LC_ALL=C find . \( ! -path './*/*' -o -prune \)
.
./St?phane
./St?phane/Chazelas
./St??phane
./St??phane/Chazelas
./John
./John/Smith

今、私は本当に得ます-maxdepth 2が、UTF-8で適切にエンコードされた2番目のステファンのéは、éのUTF-8 ??エンコーディングの0xc3 0xa9バイト(Cロケールでは2つの個別の未定義文字と見なされます)として表示されることに注意してくださいCロケールでは印刷できない文字。

を追加した場合-name '????????'、間違ったステファン(iso8859-1でエンコードされたもの)を取得していたでしょう。

の代わりに任意のパスに適用するには.、次のようにします。

find some/dir/. ! -name . -prune ...

以下のため-mindepth 1 -maxdepth 1か:

find some/dir/. \( ! -path '*/./*/*' -o -prune \) ...

のために-maxdepth 2

私はまだやる:

(cd -P -- "$dir" && find . ...)

まず、パスが短くなり、パスが長すぎる問題や引数リストが長すぎる問題に陥る可能性が低くなりますが、find任意のパス引数をサポートできないという事実を回避するためです(-fFreeBSD を除くfind$dirlike !または-print...の値


-o否定との組み合わせでは、の2つの独立したセットを実行するための一般的なトリックである-condition/を-actionfind

-action1ファイル会議で実行し、ファイル会議-condition1で独立-action2して実行する場合-condition2、次の操作はできません。

find . -condition1 -action1 -condition2 -action2

-action2唯一満たすファイルに対して実行されます両方の条件を。

また:

find . -contition1 -action1 -o -condition2 -action2

-action2一致するファイルのために実行されないの両方の条件を。

find . \( ! -condition1 -o -action1 \) -condition2 -action2

働く\( ! -condition1 -o -action1 \)に解決だろう真のすべてのファイルのために。それは想定して-action1(のようなアクションで-prune-exec ... {} +常に返すこと)。そのようなアクション-exec ... \;falseを返す可能性がある場合、GNU またはorの ように無害であるがtrueを返す別の-o -something場所を追加することができ-somethingます(ただし、上記の無効な文字に関する問題に注意してください)。-truefind-links +0-name '*'


1
いつか、たくさんの中国語ファイルに出くわします。ロケールと有効な文字についてのあなたの多くの答えを読んでとてもうれしいです。:)
ワイルドカード

2
@Wildcard、あなた(そして、さらに中国人)は、英字、フランス語...のファイル名よりも、中国のファイル名よりもファイル名に問題を起こす可能性が高いです。一般的には、比較的最近までは標準であったシングルバイト文字セットでカバーできます。中国語の文字をカバーする他のマルチバイト文字セットがありますが、これらの文字セットには多くの厄介な問題があるため、中国人は欧米人よりも早くUTF-8に切り替えると思われます。例については、編集も参照してください。
ステファンシャゼル16

0

複数のパスを検索するときに(単なるの代わりに.)深さを制限する方法が必要な問題に遭遇しました。

例えば:

$ find dir1 dir2 -name myfile -maxdepth 1

これにより、-regexを使用した別のアプローチに導かれました。要点は次のとおりです。

-regex '(<list of paths | delimited>)/<filename>'

したがって、上記は次のようになります。

$ find dir1 dir2 -name myfile -regextype awk -regex '(dir1|dir2)/myfile' # GNU
$ find -E dir1 dir2 -name myfile -regex '(dir1|dir2)/myfile' # MacOS BSD

ファイル名なし:

$ find dir1 dir2 -name myfile -maxdepth 1 # GNU

-regex '(<list of paths | delimited>)/<anything that's not a slash>$'

$ find dir1 dir2 -name myfile -regextype awk -regex '(dir1|dir2)/[^/]*$' # GNU
$ find -E dir1 dir2 -name myfile -regex '(dir1|dir2)/[^/]*$' # MacOS BSD

最後に-maxdepth 2、正規表現の変更点:'(dir1|dir2)/([^/]*/){0,1}[^/]*$'


1
ただし、この質問は標準(POSIXのような)ソリューションを求めています。また、-maxdepth複数の検索パスで動作します。
クサラナンダ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.