使用 GNU find 仅显示叶目录

发布于 2024-10-04 10:00:00 字数 183 浏览 6 评论 0原文

我正在尝试使用 GNU find 仅查找不包含其他目录的目录,但可能包含也可能不包含常规文件。

到目前为止,我最好的猜测是:

find dir -type d \( -not -exec ls -dA ';' \)

但这只会让我得到一长串“。”

谢谢!

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.

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!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

音栖息无 2024-10-11 10:00:00

如果您的文件系统符合 POSIX 标准,您可以使用 -links (即一个目录有一个指向其中每个子目录的链接、一个来自其父目录的链接以及一个指向自身的链接,因此,如果它有两个链接,则计数为 2 个链接)没有子目录)。

以下命令应该执行您想要的操作:

find dir -type d -links 2

但是,它似乎不适用于 Mac OS X(正如@Piotr 提到的)。这是另一个版本,速度较慢,但​​可以在 Mac OS X 上运行。它基于他的版本,并进行了处理目录名称中空格的更正:

find . -type d -exec sh -c '(ls -p "{}"|grep />/dev/null)||echo "{}"' \;

You can use -links if your filesystem is POSIX compliant (i.e. a directory has a link for each subdirectory in it, a link from its parent and a link to itself, thus a count of 2 links if it has no subdirectories).

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 mentioned). Here is another version that is slower, but does work on Mac OS X. It is based on his version, with a correction to handle whitespace in directory names:

find . -type d -exec sh -c '(ls -p "{}"|grep />/dev/null)||echo "{}"' \;
好菇凉咱不稀罕他 2024-10-11 10:00:00

我刚刚找到了另一个适用于 Linux 和 Linux 的解决方案。 macOS(没有 find -exec)!

它涉及 sort(两次)和 awk

find dir -type d | sort -r | awk 'a!~"^"$0{a=$0;print}' | sort

说明:

  1. 以相反顺序对 find 输出进行排序

    • 现在您的子目录首先出现,然后是其父目录
  2. 如果当前行是前缀,则使用 awk 省略行上一行的内容

    • (此命令来自此处的答案
    • 现在您消除了“所有父目录”(您只剩下父目录)
  3. 它们进行排序(所以它看起来像正常的查找 输出)
  4. 瞧!快速且便携。

I just found another solution to this that works on both Linux & macOS (without find -exec)!

It involves sort (twice) and awk:

find dir -type d | sort -r | awk 'a!~"^"$0{a=$0;print}' | sort

Explanation:

  1. sort the find output in reverse order

    • now you have subdirectories appear first, then their parents
  2. use awk to 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)
  3. sort them (so it looks like the normal find output)
  4. Voila! Fast and portable.
迷爱 2024-10-11 10:00:00

由于某些不明原因,@Sylvian 解决方案在 mac os x 上对我不起作用。所以我想出了一个更直接的解决方案。希望这会对某人有所帮助:

find . -type d  -print0 | xargs -0 -IXXX sh -c '(ls -p XXX | grep / >/dev/null) || echo XXX' ;

解释:

  • ls -p 以“/”结束目录
  • ,因此 (ls -p XXX | grep / >/dev/null) 返回 0 如果没有目录
  • -print0 && -0 是让xargs处理目录名中的空格

@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:

find . -type d  -print0 | xargs -0 -IXXX sh -c '(ls -p XXX | grep / >/dev/null) || echo XXX' ;

Explanation:

  • ls -p ends directories with '/'
  • so (ls -p XXX | grep / >/dev/null) returns 0 if there is no directories
  • -print0 && -0 is to make xargs handle spaces in directory names
温柔嚣张 2024-10-11 10:00:00

我的目录树中有一些名称奇怪的文件,这些文件使 awk 感到困惑,如下所示
@AhmetAlpBalkan 的回答。所以我采取了稍微不同的方法,

  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) 

就像在 awk 解决方案中一样,我进行了反向排序。这样,如果目录路径是前一个命中的子路径,您就可以轻松辨别这一点。

这里 p 是我之前的匹配,c 是当前匹配,l 是当前匹配的长度,f > 是上一个匹配的前 l 个匹配字符。我只回显那些与上一场比赛的开头不匹配的匹配。

所提供的 awk 解决方案的问题是,如果路径名在某些名称中包含诸如 + 之类的内容,则字符串开头的匹配似乎会混淆。子目录。这导致 awk 返回了许多误报。

I have some oddly named files in my directory trees that confuse awk as in
@AhmetAlpBalkan 's answer. So I took a slightly different approach

  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) 

As in the awk solution, I reverse sort. That way if the directory path is a subpath of the previous hit, you can easily discern this.

Here p is my previous match, c is the current match, l is the length of the current match, f is the first l matching characters of the previous match. I only echo those hits that don't match the beginning of the previous match.

The problem with the awk solution 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 awk to return a number of false positives for me.

素手挽清风 2024-10-11 10:00:00

有一种替代方法叫做 rawhide (rh),它更容易使用。

对于 btrfs 以外的文件系统:

rh 'd && nlink == 2'

对于 btrfs:btrfs

rh 'd && "[ `rh -red %S | wc -l` = 0 ]".sh'

的更短/更快的版本是:

rh 'd && "[ -z \"`rh -red %S`\" ]".sh'

上面的命令搜索目录,然后列出它们的子目录,并且仅在没有子目录时才匹配(第一个通过计算输出的行数,第二个是检查每个目录是否有任何输出)。

对于在所有文件系统上尽可能高效地工作的版本:

rh 'd && (nlink == 2 || nlink == 1 && "[ -z \"`rh -red %S`\" ]".sh)'

在普通(非 btrfs)文件系统上,这将不需要每个目录的任何额外进程,但在 btrfs 上,它将需要它们。如果您混合使用包括 btrfs 在内的不同文件系统,这可能是最好的选择。

Rawhide (rh) 可从 https://raf.org/rawhidehttps://github.com/raforg/rawhide。它至少可以在 Linux、FreeBSD、OpenBSD、NetBSD、Solaris、macOS 和 Cygwin 上运行。

免责声明:我是 rawhide 的当前作者。

There is an alternative to find called rawhide (rh) that is much easier to use.

For filesystems other than btrfs:

rh 'd && nlink == 2'

For btrfs:

rh 'd && "[ `rh -red %S | wc -l` = 0 ]".sh'

A shorter/faster version for btrfs is:

rh 'd && "[ -z \"`rh -red %S`\" ]".sh'

The above commands search for directories and then list their sub-directories and only match when there are none (the first by counting the number of lines of output, and the second by checking if there is any output at all per directory).

For a version that works on all filesystems as efficiently as possible:

rh 'd && (nlink == 2 || nlink == 1 && "[ -z \"`rh -red %S`\" ]".sh)'

On normal (non-btrfs) filesystems, this will work without the need for any additional processes for each directory, but on btrfs, it will need them. This is probably best if you have a mix of different filesystems including btrfs.

Rawhide (rh) is available from https://raf.org/rawhide or https://github.com/raforg/rawhide. It works at least on Linux, FreeBSD, OpenBSD, NetBSD, Solaris, macOS, and Cygwin.

Disclaimer: I am the current author of rawhide.

于我来说 2024-10-11 10:00:00

这个呢?它是可移植的,并且不依赖于繁琐的链接计数。但请注意,重要的是放置root/folder不带结尾的/。

find root/folder -type d | awk '{ if (length($0)<length(prev) || substr($0,1,length(prev))!=prev) print prev; prev=($0 "/") } END { print prev }'

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/folder without the trailing /.

find root/folder -type d | awk '{ if (length($0)<length(prev) || substr($0,1,length(prev))!=prev) print prev; prev=($0 "/") } END { print prev }'
牵强ㄟ 2024-10-11 10:00:00

这是适用于 Linux 和 OS X 的解决方案:

find . -type d -execdir bash -c '[ "$(find {} -mindepth 1 -type d)" ] || echo $PWD/{}' \; 

或者:

find . -type d -execdir sh -c 'test -z "$(find "{}" -mindepth 1 -type d)" && echo $PWD/{}' \;

Here is solution which works on Linux and OS X:

find . -type d -execdir bash -c '[ "$(find {} -mindepth 1 -type d)" ] || echo $PWD/{}' \; 

or:

find . -type d -execdir sh -c 'test -z "$(find "{}" -mindepth 1 -type d)" && echo $PWD/{}' \;
好菇凉咱不稀罕他 2024-10-11 10:00:00

这个 awk/sort 管道比最初提议的管道要好一点在此回答,但很大程度上基于它:)无论路径是否包含正则表达式特殊字符,它都会更可靠地工作:

find . -type d | sort -r | awk 'index(a,$0)!=1{a=$0;print}' | sort

记住awk字符串是1索引而不是0-索引,如果您习惯使用基于 C 的语言,这可能会很奇怪。

如果当前行在上一行中的索引是 1(即以它开头),那么我们会跳过它,这就像 "^"$0 的匹配一样。

This awk/sort pipe works a bit better than the one originally proposed in this answer, but is heavily based on it :) It will work more reliably regardless of whether the path contains regex special characters or not:

find . -type d | sort -r | awk 'index(a,$0)!=1{a=$0;print}' | sort

Remember that awk strings are 1-indexed instead of 0-indexed, which might be strange if you're used to working with C-based languages.

If the index of the current line in the previous line is 1 (i.e. it starts with it) then we skip it, which works just like the match of "^"$0.

我早已燃尽 2024-10-11 10:00:00

我对这个问题的看法是:

#!/bin/bash
(
while IFS= read -r -d 

它使用子 shell 来捕获运行的输出,并列出包含文件的目录。

\0' directory do files=$(ls -A "$directory" | wc -l) if test $files -gt 0 then echo "$directory" fi done < <(find . -type d -print0) ) | sort | uniq

它使用子 shell 来捕获运行的输出,并列出包含文件的目录。

My 2 cents on this problem:

#!/bin/bash
(
while IFS= read -r -d 

It uses a subshell to capture output from the run, and lists directories which have files.

\0' directory do files=$(ls -A "$directory" | wc -l) if test $files -gt 0 then echo "$directory" fi done < <(find . -type d -print0) ) | sort | uniq

It uses a subshell to capture output from the run, and lists directories which have files.

紫瑟鸿黎 2024-10-11 10:00:00

编辑:感谢@Wolf 在开篇文章的评论中发表的评论。 find "$dir" -type d -empty 有效。这对于 Stack Overlow 来说非常典型。旧帖子让您错过现代更好的解决方案。您也可以在手册中找到它。

如果有一个没有 -emptyfind 版本,那么检查的答案在我使用的文件系统 BTRFS 上不起作用,并且我对任何其他答案都不满意列于此处。使用 find 而不使用 awksed 可以得到更简单的标准答案。

find "$dir" -type d \( -exec sh -c '[ "$(/usr/bin/ls -A "{}")" ]' \; -o -print \)

sh -c '...' 调用仅对于命令替换 $(...) 是必需的。
如果您知道如何避免 \( -o -print \) 部分,请告诉我。

/usr/bin/ls 的选项可用于细化空目录的含义。 -A 还将显示隐藏的文件和文件夹(... 除外)。

对于这个简单的目的来说,它仍然有点长,但我希望这适用于任何文件系统。可能值得定义一个函数来不重复此命令。

EDIT: Thanks to @Walf for the remark in the comment of the opening post. find "$dir" -type d -empty works. It's so typical regarding Stack Overlow. Old posts make you miss the modern better solution. You can also find it in the manual.

If there is a version of find without -empty then the checked answer doesn't work on BTRFS, the filesystem that I use, and I am not satisfied with any other answer listed here. There is a simpler standard answer by using find without awk or sed.

find "$dir" -type d \( -exec sh -c '[ "$(/usr/bin/ls -A "{}")" ]' \; -o -print \)

The sh -c '…' invocation is only necessary for the command substitution $(…).
If you know how to avoid the \( -o -print \) part, let me know.

The options to /usr/bin/ls can be used to refine the meaning of an empty directory. -A will also show hidden files and folders (except . and ..).

It's still somewhat long for that simple purpose but I hope this works on any filesystem. It might be worth to define a function for not repeating this command.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文