bash 使用 GNU find 仅显示叶目录
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4269798/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Use GNU find to show only the leaf directories
提问by Thomas G Henry
I'm trying to use GNU find to find only the directories that contain no other directories, but may or may not contain regular files.
我正在尝试使用 GNU find 仅查找不包含其他目录但可能包含或不包含常规文件的目录。
My best guess so far has been:
到目前为止,我最好的猜测是:
find dir -type d \( -not -exec ls -dA ';' \)
but this just gets me a long list of "."
但这只会让我得到一长串“。”
Thanks!
谢谢!
回答by Sylvain Defresne
You can use -links if your filesystem is POSIX compliant (ie, a directory has a link for each subdirectory in it, a link from its parent and a link to self, thus a count of 2 link if it has no subdirectories).
如果您的文件系统符合 POSIX 标准,您可以使用 -links(即,一个目录中的每个子目录都有一个链接,一个来自其父目录的链接和一个到自身的链接,因此如果它没有子目录,则计数为 2 个链接)。
The following command should do what you want:
以下命令应该执行您想要的操作:
find dir -type d -links 2
However, it does not seems to work on Mac OS X (as @Piotr mentionned). Here is another version that is slower, but does work on Mac OS X. It is based on his version, with correction to handle whitespace in directory names:
但是,它似乎不适用于 Mac OS X(正如@Piotr 所提到的)。这是另一个较慢的版本,但可以在 Mac OS X 上运行。它基于他的版本,并更正以处理目录名称中的空格:
find . -type d -exec sh -c '(ls -p "{}"|grep />/dev/null)||echo "{}"' \;
回答by AhmetB - Google
I just found another solution to this that works on both Linux & macOS (without find -exec)!
我刚刚找到了另一个适用于 Linux 和 macOS(没有find -exec)的解决方案!
It involves sort(twice) and awk:
它涉及sort(两次)和awk:
find dir -type d | sort -r | awk 'a!~"^"find . -type d -print0 | xargs -0 -IXXX sh -c '(ls -p XXX | grep / >/dev/null) || echo XXX' ;
{a=find root/folder -type d | awk '{ if (length(find . -type d -execdir bash -c '[ "$(find {} -mindepth 1 -type d)" ] || echo $PWD/{}' \;
)<length(prev) || substr(find . -type d -execdir sh -c 'test -z "$(find "{}" -mindepth 1 -type d)" && echo $PWD/{}' \;
,1,length(prev))!=prev) print prev; prev=( p=;
while read c;
do
l=${#c};
f=${p:0:$l};
if [ "$f" != "$c" ]; then
echo $c;
fi;
p=$c;
done < <(find . -type d | sort -r)
"/") } END { print prev }'
;print}' | sort
Explanation:
解释:
sort the
findoutput in reverse order- now you have subdirectories appear first, then their parents
use
awkto omit lines if the current line is a prefix of the previous line- (this command is from the answer here)
- now you eliminated "all parent directories" (you're left with parent dirs)
sortthem (so it looks like the normalfindoutput)- Voila! Fast and portable.
回答by Piotr Czapla
@Sylvian solution didn't work for me on mac os x for some obscure reason. So I've came up with a bit more direct solution. Hope this will help someone:
@Sylvian 解决方案在 mac os x 上对我不起作用,原因不明。所以我想出了一个更直接的解决方案。希望这会帮助某人:
##代码##Explanation:
解释:
ls -pends directories with '/'- so
(ls -p XXX | grep / >/dev/null)returns 0 if there is no directories -print0&&-0is to make xargs handle spaces in directory names
ls -p以“/”结束目录- 所以
(ls -p XXX | grep / >/dev/null)如果没有目录则返回 0 -print0&&-0是让 xargs 处理目录名中的空格
回答by DREV
What about this one ? It's portable and it doesn't depend on finnicky linking counts. Note however that it's important to put root/folderwithoutthe trailing /.
这个如何 ?它是便携式的,不依赖于 finnicky 链接计数。但是请注意,root/folder不带尾随 /很重要。
回答by kenorb
Here is solution which works on Linux and OS X:
这是适用于 Linux 和 OS X 的解决方案:
##代码##or:
或者:
##代码##回答by A.Ellett
I have some oddly named files in my directory trees that confuse awkas in
@AhmetAlpBalkan 's answer. So I took a slightly different approach
我的目录树中有一些命名奇怪的文件,awk就像@AhmetAlpBalkan 的回答一样令人困惑。所以我采取了稍微不同的方法
As in the awksolution, I reverse sort. That way if the directory path is a subpath of the previous hit, you can easily discern this.
在awk解决方案中,我反向排序。这样,如果目录路径是前一个命中的子路径,您就可以轻松辨别这一点。
Here pis my previous match, cis the current match, lis the length of the current match, fis the first lmatching characters of the previous match. I only echothose hits that don't match the beginning of the previous match.
这里p是我之前的匹配,c是当前匹配,l是当前匹配的长度,f是l之前匹配的第一个匹配字符。我只有echo那些与上一场比赛的开头不匹配的点击。
The problem with the awksolution offered is that the matching of the beginning of the string seems to be confused if the path name contains things such as +in the name of some of the subdirectories. This caused awkto return a number of false positives for me.
所提供的awk解决方案的问题在于,如果路径名包含+某些子目录的名称等内容,则字符串开头的匹配似乎会混淆。这导致awk我返回了许多误报。

