当前:
$ find -type d
./a
./a/sub
./b
./b/sub
./b/sub/dub
./c/sub
./c/bub
我需要:
$ find -type d -not -contains -type d
./a/sub
./b/sub/dub
./c/sub
./c/bub
如何排除包含其他(子)目录但不为空(包含文件)的目录?
查找
只有2个链接(或更少)的叶目录,然后检查每个找到的目录是否包含一些文件。# find leaf directories
find -type d -links -3 -print0 | while read -d '' dir
do
# check if it contains some files
if ls -1qA "$dir" | grep -q .
then
echo "$dir"
fi
done
find -type d -links -3 ! -empty
-noleaf
选项进行查找。但在WSL2中,它可以不用。
在btrfs文件系统中,目录始终只有1个链接,因此在那里使用-links
是行不通的。
一个更慢但与文件系统无关的基于find
的版本:
prev='///' # some impossible dir
# A depth first find to collect non-empty directories
readarray -d '' dirs < <(find -depth -type d ! -empty -print0)
for dir in "${dirs[@]}"
do
dirterm=$dir'/'
# skip if it matches the previous dir
[[ $dirterm == ${prev:0:${#dirterm}} ]] && continue
# skip if it has sub directories
[[ $(find "$dir" -mindepth 1 -maxdepth 1 -type d -print -quit) != '' ]] && continue
echo "$dir"
prev=$dir
done # add "| sort" if you want the same order as a "find" without "-depth"
btrfs
上不起作用,因为btrfs
中目录的链接计数与经典Unix文件系统不同。 - M. Nejat Aydinbtrfs
目录会显示多少个链接?小于2吗?如果是这样,那么可能会通过我的最新编辑进行修复。 - Ted Lyngmo你没有告诉我们这些目录中哪些包含文件,哪些不包含。由于您指定了文件,因此我假设您只想要没有子目录但有文件的目录。
shopt -s dotglob nullglob globstar # customize glob evaluation
for d in **/ # loop directories only
do for s in "${d}"*/ # check subdirs in each
do [[ -h "$s" ]] || continue 2 # skip dirs with subdirs
done
for f in "${d}"* # check for nondirs in each
do echo "$d" # there's something here!
continue 2 # done with this dir, check next
done
done
dotglob
选项包括以“点”(.foo
)开头的“隐藏”文件。nullglob
选项使 no*such
返回 nothing 而不是字符串 'no*such'。globstar
选项使 **/
匹配任意深度——例如,./x/
、./x/y/
和 ./x/y/z/
。for d in **/
循环遍历所有子目录,包括子目录的子目录,尽管尾随的 /
表示只报告目录,而不是文件。for s in "${d}"*/
循环遍历 $d
的所有子目录(如果有)。nullglob
意味着如果没有子目录,则不会执行循环。如果我们看到一个子目录,[[ -h "$s" ]] || continue 2
表示如果它进入了这个循环,符号链接是可以的,但其他任何内容都会使 $d
失效,所以跳过 2 个封闭循环并将顶级推进到下一个目录。如果到达这一步,就没有无效的真实子目录,因此我们必须确认存在某种类型的文件,即使它们只是指向其他目录的符号链接。 for f in "${d}"*
循环遍历目录中的任何其他内容,因为我们知道没有子目录。由于 nullglob
的原因,如果目录没有任何东西,它甚至不会进入循环,因此如果它进入循环,则其中任何内容都是报告该目录(echo "$d"
)作为非空的原因。完成后,就没有继续检查的理由了,所以 continue 2
再次将顶级循环推进到要检查的下一个目录!
我希望 **/
能够工作,但在我的 Windows/Git Bash 模拟器上它无法获取任何子目录。**/*/
忽略当前目录的子目录,这就是我最初使用 */ **/*/
的原因,但 **/
在正确的 Centos VM 上运行时可以避免冗余。请使用它。
#
很容易打开/关闭该功能。 - Paul Hodges-not -contains -type d
所示(除目录外的所有内容)。之前没有澄清,敬请谅解。 - u15p7fgy863eiq5
find -type d
,但只对树的叶节点感兴趣。这里有一个方法:执行find -type d|sort
并将结果传递到循环中。每当你有两个连续的行 X 和 Y,并且行 Y 的长度不大于行 X 的长度时,行 X 必须是你感兴趣的目录。 - user1934428find -type d -links 2 ! -empty
。(参见(U&L) How to find only directories without subdirectories?)请注意,对于某些文件系统(如BTRFS),此命令可能无法正常工作。 - kvantour