使用“查找”仅列出没有子目录的目录

Mao*_*oPU 5 linux command-line

如何只列出没有另一个子目录的目录?

想象一个像/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帮助(我无法让它按照我想要的方式做出反应)?

Gil*_*il' 5

这是一个符合 POSIX 的解决方案,它对 的输出进行后处理find以删除具有列出的子目录的目录。它假定目录名称中没有换行符。

{ find . -type d; echo; } |
awk 'index($0,prev"/")!=1 && NR!=1 {print prev}
     1 {sub(/\/$/,""); prev=$0}'
Run Code Online (Sandbox Code Playgroud)

说明:awk 脚本会延迟每一行的打印,直到它读取下一行,并且如果它不是前缀,则只打印上一行。这利用了在find其父目录之后立即列出子目录的事实。额外的"/"是避免foofoobar也存在时虚假删除。不优雅NR!=1避免打印初始空行,不优雅echo;是不要对最后一行有同样不优雅的特殊情况。调用sub从顶级目录中删除尾部斜杠,以防 egfind ./被调用。


像往常一样,有一个神秘的 zsh one-liner。

echo **/.(e\''test -z $REPLY/*(/DN[1])'\':h)
Run Code Online (Sandbox Code Playgroud)

更长、更易读的版本:

is_leaf () { [ -z $REPLY/*(/DN[1]) ] }
echo **/.(+is_leaf:h)
Run Code Online (Sandbox Code Playgroud)

最后一行可以简化为echo **/(+is_leaf),如果你不”介意尾随/

摘要说明:括号中的内容是glob qualifiers,记录在zshexpn手册页中。我们过滤 glob 的结果**/(扩展到当前目录及其所有子目录),只保留那些函数is_leaf(或 之间的代码'…')返回 0 的结果。过滤器代码 globs 正在测试的匹配项的子目录$REPLY(在事实上,[1]使它在第一个子目录之后停止)并返回一个状态,指示是否至少找到一个子目录。glob 限定符/限制对目录的扩展;N表示如果没有匹配则扩展为空;D导致包含点文件;:h是历史修饰符并导致/.要去除的后缀(通常是指dirname)。

只是为了说明 zsh 的 glob 限定符的可能性,这里有两个具有相应is_leaf功能的其他变体(更长,我认为更模糊):

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:) }
Run Code Online (Sandbox Code Playgroud)