findコマンドで最小深度を選択的に適用できますか?

findコマンドで最小深度を選択的に適用できますか?

次のファイル階層があります。

data
├── debug.log
├── messages
│   ├── msg001.txt
│   ├── msg002.txt
│   └── msg003.txt
└── pictures
    ├── msg002
    │   └── pic001.jpg
    └── msg003
        ├── pic001.jpg
        └── pic002.jpg

最初の2つのレベル(データ、データ/メッセージ、データ/画像)の下のすべてのファイルとすべてのディレクトリを見つけたいです。階層の固定構造の一部ではないすべて(該当する場合)。

シングル検索呼び出しでこれを実行できますか?

次のファイルがあります。

$ find data -type f | sort
data/debug.log
data/messages/msg001.txt
data/messages/msg002.txt
data/messages/msg003.txt
data/pictures/msg002/pic001.jpg
data/pictures/msg003/pic001.jpg
data/pictures/msg003/pic002.jpg

ディレクトリを見つけることができます:

$ find data -mindepth 2 -type d | sort
data/pictures/msg002
data/pictures/msg003

ただし、-minlengthはテストではなくオプションなので、それらを組み合わせることはできません。

$ find data -type f -o \( -mindepth 2 -type d \) | sort
find: warning: you have specified the -mindepth option after a non-option argument -type, but options are not positional (-mindepth affects tests specified before it as well as those specified after it). Please specify options before other arguments.

data/messages/msg001.txt
data/messages/msg002.txt
data/messages/msg003.txt
data/pictures/msg002
data/pictures/msg002/pic001.jpg
data/pictures/msg003
data/pictures/msg003/pic001.jpg
data/pictures/msg003/pic002.jpg

(data/debug.logはここにありません。)

階層の深さを実際のテストと見なす方法はありますか?

私が考えることができる最高の組み合わせは、パスで正規表現を使用してディレクトリの最初の2つのレベルを識別することです。

$ find data -type f -o \( -type d -regextype posix-extended \! -regex 'data(/[^/]+)?' \) | sort

答え1

階層の深さを実際のテストと見なす方法はありますか?

にありますFreeBSDを探す-depth N条件もあります:

% find data -type f -o -depth +1 -type d |sort
data/debug.log
data/messages/msg001.txt
data/messages/msg002.txt
data/messages/msg003.txt
data/pictures/msg002
data/pictures/msg002/pic001.jpg
data/pictures/msg003
data/pictures/msg003/pic001.jpg
data/pictures/msg003/pic002.jpg

(はい、-depthそのオプションと混同しやすいです。)

「固定構造」(IMO、構造が実際に固定されているかどうかを知る必要があります)の一部であるディレクトリのセットを知っている場合は、次のディレクトリを除外できます。

% find data ! -path data ! -path data/messages ! -path data/pictures
...

またはgrepと同じです。

% find data | grep -vEe '^(data|data/(pictures|messages))$'
...

find(代わりにデフォルトの出力形式を使用したため、find -print0ファイル名に改行文字が含まれていない可能性があります)

答え2

これは-mindepth非標準拡張です(もともとはGNUから来ましたが、find後で他の実装に追加されます)。対照的に-maxdepth、標準述部で簡単にシミュレートされます。たとえば、LC_ALL=C find . -path './*/*'GNUエミュレーションですfind . -mindepth 2

だからここにあります:

LC_ALL=C find data '(' -type d -path '*/*/*' -o -type f ')' -print0 |
  sort -z |
  tr '\0' '\n'

findsort(ファイルパスは複数行で構成される可能性があるため、NULで区切られたレコードを使用しない限り、出力をパイプで接続することはできません。-print0現在は一般的ですが(すぐにPOSIXになる予定ですが、あまり一般的ではありません)、-zGNU拡張です。-print0-z

答え3

最善の方法ではありませんが、GNUを使用して次のことができますfind

find data -printf '%d\0%y\0%p\n' | awk -F '\0' '$2 == "f" || $2 == "d" && $1 >= 2 {print $3}'

findこの-printfフラグを使用すると、次のフィールドが印刷されます(ヌル文字 - で区切られます\0)。

  %d     File's depth in the directory tree; 0 means the file is a starting-point.
  %y     File's type (like in ls -l), U=unknown type (shouldn't happen)
  %p     File's name.

その後、コマンドはawk深さが2()以上のすべてのファイル()とディレクトリの名前を印刷します。$2 == "f"$2=="d" && $1 >= 2

答え4

免責事項:私はこの回答に使用されている生皮(rh)プログラムの現在の作成者です(参照https://github.com/raforg/rawhide)。

そして右回転、次のようにすることができます。

rh data 'f || (d && depth >= 2)'

ディレクトリ内の少なくとも2()の深さのdataファイル(f)とディレクトリ()を検索します。ddepth >= 2

Linux、FreeBSD、OpenBSD、NetBSD、macOS、Solaris、およびCygwinで動作します。

関連情報