linux中有没有一种方法可以在目录树中仅查找那些作为分支末端的目录(我在这里将它们称为叶子),即其中没有子目录的目录?我在看这个问题但从未得到正确的答复。
所以如果我有一个目录树
root/
├── branch1
│ ├── branch11
│ │ └── branch111 *
│ └── branch12 *
└── branch2
├── branch21 *
└── branch22
└── branch221 *
我可以只找到其分支末尾的目录(标有 的目录*
),所以只查看目录的数量,而不是文件的数量吗?在我的真实案例中,我正在寻找带有文件的文件,但它们是我想在本示例中找到的“叶子”的子集。
答案1
要仅查找包含非目录文件的叶目录,您可以结合引用问题的答案https://unix.stackexchange.com/a/203991/330217或类似问题https://stackoverflow.com/a/4269862/10622916或者https://serverfault.com/a/530328与find
的! -empty
find rootdir -type d -links 2 ! -empty
检查硬链接-links 2
应该适用于传统的 UNIX 文件系统。该-empty
条件不是 POSIX 标准的一部分,但应该在大多数 Linux 系统上可用。
根据 KamilMaciorowski 的评论,目录的传统链接计数语义对于 Btrfs 无效。这在https://linux-btrfs.vger.kernel.narkive.com/oAoDX89D/btrfs-st-nlink-for-directories其中还提到 Mac OS HFS+ 作为传统行为的例外。对于这些文件系统,需要使用不同的方法来检查叶目录。
答案2
您可以使用嵌套find
并计算子目录的数量:
find . -type d \
\( -exec sh -c 'find "$1" -mindepth 1 -maxdepth 1 -type d -print0 | grep -cz "^" >/dev/null 2>&1' _ {} \; -o -print \)
答案3
和zsh
:
leafdirs=( **/*(NDFl2) )
$leafdirs
使用匹配的叶目录列表设置数组。
您可以使用以下命令在列上print
列出r
aw 1
C
:
print -rC1 -- $leafdirs
或者使用以下命令循环它们:
for dir ($leafdirs) something with $dir
这或多或少是翻译@Bodo 的 GNUfind
答案,就像它只适用于传统的类 Unix 文件系统(如ext4
该实现).
和..
实际的目录条目一样。
**/
:任何级别的子目录(NDFl2)
: 全局限定符N
:启用nullglob
该 glob:如果没有匹配,则不会失败。相反,结果是一个空列表D
:启用dotglob
该 glob:查看隐藏目录,并且不要跳过隐藏文件F
: 选择满的目录:至少包含一个除.
和以外的条目的目录..
(如 GNUfind
的-type d ! -empty
)l2
:仅链接计数为 2 的目录(如-links 2
)。一种用于其父目录中的目录条目,另一种用于.
其中的目录条目。由于..
其中的条目,任何子目录都会为链接计数加一。
在无法使用 nlinks == 2 的文件系统上,您可以执行以下操作:
leafdirs=( **/*(NDF^e['()(($#)) $REPLY/*(ND/Y1)']) )
我们使用e
限定符(用 否定^
)运行代码来检查目录(存储在该代码中)是否有子目录,这里使用匿名函数来检查中的目录$REPLY
的扩展是否在第一个匹配处停止,传递的参数是一个非空列表(非零)。$REPLY/*(ND/Y1)
$REPLY
$#
答案4
如果*/
文件名通配模式扩展为不是目录名称的内容,则当前目录没有(非隐藏)子目录。
和find
:
find root -type d -exec sh -c 'set -- "$1"/*/; [ ! -d "$1" ]' sh {} \; ! -empty -print
请注意,这会将叶目录中的目录的符号链接视为目录,因为该模式将遍历符号链接。
该-empty
谓词不是标准的,但经常被实现。如果没有它,您将执行与检测子目录类似的操作:
find root -type d \
-exec sh -c 'set -- "$1"/*/; [ ! -d "$1" ]' sh {} \; \
-exec sh -c 'set -- "$1"/*; [ -e "$1" ]' sh {} \; -print
或者,更有效一点,
find root -type d -exec sh -c '
dir=$1
set -- "$dir"/*/
[ -d "$1" ] && exit 1
set -- "$dir"/*
[ -e "$1" ]' sh {} \; -print
或者,采用-links
我已经忘记的谓词(谢谢博多):
find root -type d \
-links 2 \
-exec sh -c 'set -- "$1"/*; [ -e "$1" ]' sh {} \; -print