POSIX照会を特定の深さに制限しますか?

POSIX照会を特定の深さに制限しますか?

最近気づきました。POSIX仕様find-maxdepthジュニアレベルは除外されます。

慣れていない人のために説明すると、主な目的は -maxdepth下降の深さを制限することです。明らかにするfind-maxdepth 0ただ処理中のコマンドライン引数、-maxdepth 1結果はコマンドライン引数などでのみ直接処理されます。

-maxdepthPOSIX指定オプションとツールのみを使用してPOSIX以外のマスターデータベースと同じ動作を得るにはどうすればよいですか?

-maxdepth 0(注:もちろん、最初のオペランドとして使用して同じ結果を得ることはできますが、-prune他の深さには拡張されません。)

答え1

@meuhの-maxdepth 1アプローチは、まだfindレベル1ディレクトリの内容を読んでから無視できるため、非効率的です。また、一部のディレクトリ名に、ユーザーロケールで有効な文字を形成しないバイトシーケンスが含まれている場合(たとえば、他の文字エンコーディングのファイル名など)、find一部の実装(GNUを含む)では正しく機能しません。find

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

これはGNUを実装するより標準化された方法です-maxdepth 1

-mindepth 1 -maxdepth 1一般的に言えば、(深さ0)について考えたくないので、望む深さは1()です。.これははるかに簡単です。

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

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

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

ここで無効な文字の問題が発生します。

たとえば、ディレクトリがありますが、iso8859-1(latin1とも呼ばれる)文字セット(0xe9バイト)でエンコードされている場合Stéphaneé2000年代半ばまで西ヨーロッパと米国で最も一般的です)、0xe9バイトUTF-8では有効な文字ではありません。したがって、UTF-8ロケールでは、*ワイルドカード(一部の実装の場合)が0以上なので一致findしません。Stéphane*数値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

鉱山は、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 22番目のStéphaneのéはUTF-8で正しくエンコードされ、éに対して??UTF-8でエンコードされた0xc3 0xa9バイトとして表示されます(Cロケール単一の未定義文字では2として扱われます)。 ): C ロケールで印刷できない文字です。

を追加すると、-name '????????'無効なStéphane(iso8859-1でエンコードされたもの)が表示されます。

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

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

または-mindepth 1 -maxdepth 1:

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

のための-maxdepth 2

私はまだ一つを作ります:

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

第1に、これは経路が短くなり、遭遇する可能性が減少するからである。パスが長すぎますまたは引数のリストが長すぎます。これは問題であるだけでなく、find任意のパスパラメータをサポートできないという事実(-fFreeBSDを除く)を処理するためです。なぜなら、任意のパスパラメータはまたは...などのfind値のために窒息する可能性があるからです。$dir!-print


否定との組み合わせは、/ inの-o2つの別々のセットを実行する一般的なトリックです。-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 ... \;返されることがあります。間違った、無害ですが返される別の-o -something場所を追加できます。-something本物-trueGNUのfindor-links +0または! -name ''orと同じです-name '*'(無効な文字については上記を参照してください)。

答え2

これを使用して、-path与えられた深さを一致させ、そこからトリミングすることができます。例えば

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

*match .*/*match ./dir1、matchが切り捨てられるため、最大深さは1です*/*/*./dir1/dir2絶対起動ディレクトリを使用している場合は/前に-path

答え3

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

たとえば、

$ 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}[^/]*$'

関連情報