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
表示できます。r
1
C
print -rC1 -- $leafdirs
または、次のように繰り返します。
for dir ($leafdirs) something with $dir
これはほぼ翻訳です。@BodoのGNUのfind
答え、これは従来のUnixファミリーファイルシステム(ext4
この実装と同じ).
と..
実際のディレクトリエントリでのみ機能するのと同じです。
**/
: すべてのレベルのサブディレクトリ(NDFl2)
: グローバル予選N
:nullglob
この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