別の子ディレクトリを持たないディレクトリだけを一覧表示するにはどうすればよいでしょうか?
のみをリストするために/A /A/AA /A/AB /A/AB/ABB /B /C /C/CC /C/CC/CCC /C/CC/CCC/CCCC
使用したいような構造を想像してください。find
/A/AA /A/AB/ABB /B /C/CC/CCC/CCCC
出発点は ですfind . -type d
が、 も も使用できず、役に立ちますか-mindepth
(期待どおりに反応させることができませんでした)?-maxdepth
-noleaf
答え1
以下は、 の出力を後処理して、find
リストされているサブディレクトリを持つディレクトリを削除する POSIX 準拠のソリューションです。ディレクトリ名に改行が含まれていないことを前提としています。
{ find . -type d; echo; } |
awk 'index($0,prev"/")!=1 && NR!=1 {print prev}
1 {sub(/\/$/,""); prev=$0}'
説明: awk スクリプトは、次の行が読み込まれるまで各行の印刷を遅らせ、プレフィックスでない場合のみ前の行を印刷します。これは、find
サブディレクトリを親の直後にリストするという事実を利用しています。余分なのは、も存在する場合に"/"
誤って削除されるのを避けるためです。不格好なのは、最初の空行の印刷を回避し、不格好なのは、最後の行に同様に不格好な特別なケースを持たないようにするためです。 の呼び出しは、 egが呼び出された場合に備えて、トップレベル ディレクトリから末尾のスラッシュを削除します。foo
foobar
NR!=1
echo;
sub
find ./
いつものように、難解な zsh ワンライナーがあります。
echo **/.(e\''test -z $REPLY/*(/DN[1])'\':h)
より長く、読みやすいバージョン:
is_leaf () { [ -z $REPLY/*(/DN[1]) ] }
echo **/.(+is_leaf:h)
echo **/(+is_leaf)
末尾の を気にしないのであれば、最後の行は と簡略化できます/
。
要約説明: 括弧内のものはglob 修飾子、マニュアルページに記載されていますzshexpn
。glob の結果をフィルタリングし**/
(現在のディレクトリとそのすべてのサブディレクトリに展開)、関数is_leaf
(または の間のコード'…'
) が 0 を返すものだけを保持します。フィルタ コードは、テストされている一致のサブディレクトリ ( $REPLY
) を glob し (実際には、[1]
最初のサブディレクトリの後に停止します)、少なくとも 1 つのサブディレクトリが見つかったかどうかを示すステータスを返します。glob 修飾子は、/
展開をディレクトリに制限します。N
一致がない場合は展開が空になることを意味し、D
ドット ファイルが含まれるようになります。:h
は履歴修飾子であり、/.
サフィックスが削除されます (一般的には を意味しますdirname
)。
zsh の glob 修飾子の可能性を説明するために、対応するis_leaf
関数を持つ他の 2 つのバリエーション (より長く、よりわかりにくいと思います) を次に示します。
echo **/.(e\''tmp=($REPLY/*(/DN[1])); ((!#tmp))'\':h)
echo **/.(e\''$REPLY/*(/DN[1]e:REPLY=false:)'\':h)
is_leaf () { set -- $REPLY/*(/DN[1]); ((!#)); }
is_leaf () { return $REPLY/*(/DN[1]e:REPLY=1:) }
答え2
私が使用しているのは次のものです:
leaf () { find "${1:-.}" -depth -type d | sed 'h; :b; $b; N; /^\(.*\)\/.*\n\1$/ { g; bb }; $ {x; b}; P; D'; }
開始するディレクトリを使用して呼び出します:
leaf /start/dir
答え3
サブディレクトリのないディレクトリを検索するには:
find dir -type d -links 2
説明: ディレクトリには、その中の各サブディレクトリへのリンク、その親からのリンク、およびディレクトリ自体へのリンクがあるため、サブディレクトリがない場合、リンクの数は 2 になります。