サブディレクトリなしでディレクトリのみを検索するには? [コピー]

サブディレクトリなしでディレクトリのみを検索するには? [コピー]

Linuxには、ディレクトリツリーでブランチの終わり(ここでは葉と呼びます)であるディレクトリ、つまりサブディレクトリがないディレクトリだけを見つける方法はありますか?私が探していますこの問題しかし、一度もきちんとした答えが得られませんでした。

だからディレクトリツリーがあれば

root/
├── branch1
│   ├── branch11
│   │   └── branch111   *
│   └── branch12        *
└── branch2
    ├── branch21        *
    └── branch22
        └── branch221   *

分岐の終わり(ラベル付きディレクトリ*)でのみディレクトリを見つけることができるので、ファイル数ではなくディレクトリ数だけを見ることはできますか?実際のケースでは、ファイルを含むファイルを探していますが、そのファイルはこの例で探している「葉」のサブセットです。

答え1

ディレクトリ以外のファイルを含むリーフディレクトリのみを見つけるには、引用した質問に対する回答を組み合わせてください。https://unix.stackexchange.com/a/203991/330217または同様の質問https://stackoverflow.com/a/4269862/10622916またはhttps://serverfault.com/a/530328findとともに! -empty

find rootdir -type d -links 2 ! -empty

ハードリンク検証は、-links 2既存のUNIXファイルシステムで機能します。この-empty条件は POSIX 標準の一部ではありませんが、ほとんどの Linux システムで使用できます。

KamilMaciorowskiのコメントによると、ディレクトリの伝統的なリンク数の意味はBtrfsには無効です。これはhttps://linux-btrfs.vger.kernel.narkive.com/oAoDX89D/btrfs-st-nlink-for-directoriesMac OS HFS+は、既存の動作の例外としても呼ばれます。これらのファイルシステムの場合、リーフディレクトリを確認するには別の方法が必要です。

答え2

findネストを使用してサブディレクトリの数を数えることができます。

find . -type d \
  \( -exec sh -c 'find "$1" -mindepth 1 -maxdepth 1 -type d -print0 | grep -cz "^" >/dev/null 2>&1' _ {} \; -o -print \)

答え3

そしてzsh

leafdirs=( **/*(NDFl2) )

$leafdirs一致するリーフディレクトリのリストに配列を設定します。

以下を使用して、列にawを一覧print表示できます。r1 C

print -rC1 -- $leafdirs

または、次のように繰り返します。

for dir ($leafdirs) something with $dir

これはほぼ翻訳です。@BodoのGNUのfind答え、これは従来のUnixファミリーファイルシステム(ext4この実装と同じ)...実際のディレクトリエントリでのみ機能するのと同じです。

  • **/: すべてのレベルのサブディレクトリ
  • (NDFl2): グローバル予選
  • Nnullglobこのglobを有効にします。一致するものがなくても失敗しません。代わりに、結果は空のリストです。
  • D:このglobを有効にするdotglob:隠しディレクトリを見て隠しファイルをスキップしません。
  • F:選択するいっぱいディレクトリ:.およびそれ以外の項目を1つ以上含むディレクトリ..(GNUfindに似ています-type d ! -empty
  • l2:数が2つのディレクトリのみを接続します(例-links 2:)。 1つは親ディレクトリ内のディレクトリエントリ用、もう1つは.親ディレクトリ内のディレクトリエントリ用です。すべてのサブディレクトリには、そのエントリのためにリンク..数に1つが追加されます。

nlinks == 2が不可能なファイルシステムでは、次のことができます。

leafdirs=( **/*(NDF^e['()(($#)) $REPLY/*(ND/Y1)']) )

(このコードに保存されている)ディレクトリにサブディレクトリがあることを確認するには、修飾子e(negationを含む)を使用してコードを実行します。ここでは、匿名関数を使用して、ディレクトリ拡張が最初の一致で停止することを確認します。渡された引数はAです。空でないリスト(ゼロではない)。^$REPLY$REPLY/*(ND/Y1)$REPLY$#

答え4

ファイル名ワイルドカードパターンがディレクトリ名以外の名前に拡張されると、*/現在のディレクトリに隠されているサブディレクトリが存在しません。

そしてfind

find root -type d -exec sh -c 'set -- "$1"/*/; [ ! -d "$1" ]' sh {} \; ! -empty -print

パターンはシンボリックリンクを通過するため、リーフディレクトリ内のディレクトリへのシンボリックリンクをディレクトリとして扱います。

この-empty述部は標準ではありませんが、頻繁に実装されます。これがなければ、サブディレクトリを検索するのと同様の操作を実行します。

find root -type d \
    -exec sh -c 'set -- "$1"/*/; [ ! -d "$1" ]' sh {} \; \
    -exec sh -c 'set -- "$1"/*;  [   -e "$1" ]' sh {} \; -print

またはより効果的に、

find root -type d -exec sh -c '
    dir=$1
    set -- "$dir"/*/
    [ -d "$1" ] && exit 1
    set -- "$dir"/*
    [ -e "$1" ]' sh {} \; -print

または、-links私が忘れた述語を選択してください(ありがとう、博多):

find root -type d \
    -links 2 \
    -exec sh -c 'set -- "$1"/*; [ -e "$1" ]' sh {} \; -print

関連情報