find . -type d
一般会显示
./dir1
./dir1/dir2
./dir3
./dir3/dir4
./dir3/dir4/dir5
...
我只想
./dir1/dir2
./dir3/dir4/dir5
,没有其父级 ./dir1,...
换句话说,我只想查看其中没有任何子目录的目录。
任何想法?
编辑:我发现它-links 2
可以在正常的Linux环境中工作,例如,
docker run -it --rm ubuntu:bionic find /etc -type d -links 2
工作完美。
但是,当我将目录(从 MacOS 或 Windows)安装到 docker 容器中时,情况发生了变化,它不起作用,您可以尝试以下操作:
docker run -it --rm -v /etc:/etc_of_host ubuntu:bionic find /etc_of_host -type d -links 2
答案1
和zsh
:
has_subdirs() () (( $# )) ${1-$REPLY}/*(ND/Y1)
print -rC1 -- **/*(ND/^+has_subdirs)
或者直接不带中介函数:
print -rC1 -- **/*(ND/^e['()(($#)) $REPLY/*(ND/Y1)'])
那是:
fn() some-command
定义一个fn
函数作为some-command
主体,就像 Bourne-shell 和大多数类似 Bourne 的 shell 中一样。() { code } args
作为位置参数运行code
的匿名函数。args
(( $# ))
这里匿名函数的主体是一个算术表达式,它解析为真的if$#
(参数数量)非零。${param-default}
(来自 Bourne shell)扩展为$param
是否设置了参数或default
其他情况。在这里${1-$REPLY}
,我们允许直接调用我们的函数(如has_subdirs mydir
)或作为如下所示的全局限定符函数。$dir/*(ND/Y1)
$dir
扩展到( )中目录类型的文件,/
包括隐藏文件 (D
otglob ),并且如果没有匹配 (N
ullglob ),也不会出错。但是对于Y1
,我们停在第一场比赛。因此has_subdirs
,如果目录至少包含一个子目录,则匿名函数(因此)将返回 true。print -rC1
在olumn上打印其参数r
aw1
C
^+has_subdirs
仅限于该has_subdirs
函数未 (^
) 返回 true 的文件。
如果必须使用bash
shell,只需执行以下操作:
zsh << 'EOF'
print -rC1 -- **/*(ND/^e['()(($#)) $REPLY/*(ND/Y1)'])
EOF
或者将结果存储在 bash 数组中(需要 bash-4.4+):
readarray -td '' array < <(zsh << 'EOF'
print -rNC1 -- **/*(ND/^e['()(($#)) $REPLY/*(ND/Y1)'])
EOF
)
(使用 NUL 分隔的记录以便能够存储任意路径)。
如果你没有zsh
,但你有perl
,你可以这样做:
find . -depth -type d -print0 |
perl -l -0ne 'print if rindex $prev, "$_/", 0; $prev = $_'
或者如果你有 GNU awk
:
find . -depth -type d -print0 |
gawk -v 'RS=\0' 'index(prev, $0"/") != 1; {prev = $0}'
那些已经find
打印了目录深度优先(在它们所在的分支之前离开)并获取perl
/awk
打印未找到的记录,然后/
在上一条记录的开头。
同样,要将文件存储在 bash 4.4+ 数组中,您需要通过移动 after-l
或add in 来-0
在输出上切换到 NUL 分隔记录:perl
-v 'ORS=\0'
gawk
readarray -td array < <(
find . -depth -type d -print0 |
perl -0lne 'print if rindex $prev, "$_/", 0; $prev = $_'
)
readarray -td array < <(
find . -depth -type d -print0 |
gawk -v 'RS=\0' -v 'ORS=\0' 'index(prev, $0"/") != 1; {prev = $0}'
)
在某些系统和文件系统(例如ext4
基于 Linux 的系统上的文件系统)上,您可能可以依赖这样一个事实:具有子目录的目录的链接计数大于 2(dir
,dir/.
以及每个 的附加链接dir/subdir/..
)。
print -rC1 -- **/*(ND/l-3)
find
或者在任何 shell 中使用:
find . -type d -links -3
这在目录的链接计数始终为 1 的情况下不起作用btrfs
(在多个 Linux 发行版中已被替换为默认文件系统),因此我不建议将其作为通用解决方案。ext4
联合文件系统与您的情况相同,例如overlayfs
我找到一些合并目录的链接计数为 1,无论它们是否包含子目录。
但是,无论在哪里可用,它都比手动计算子目录的解决方案具有优势,即您不需要对目录进行读取访问(只需对其父目录进行搜索访问)。
答案2
您要寻找的是:
find . -type d -links 2
文件系统中的每个目录至少有两个硬链接 - 父目录中的目录本身和“.”入口。子目录中的每个“..”条目都会向目录添加一个新的硬链接。所以你只需要找到有两个硬链接的目录即可。
另一个答案中建议的命令
find . -type d -links -3
执行相同的操作,但声明“少于三个硬链接的目录”。
答案3
最排序:
p="";(find . -type d;echo) | while read d; do [[ $p && $d != $p/* ]] && echo $p; p=$d; done
在一行中
a="";(find . -type d;echo )|while read i; do if [[ (! $i =~ $a) && ("$a" != "") ]]; then echo $a; fi; a=$i;done
正如op提到的:
a="";(find . -type d;echo )|while read i; do [[ $i != $a/* && ! -z "$a" ]] && echo $a; a=$i;done
答案4
读man find
。该-mindepth
选项就是您想要的。