如何删除子树中的所有空目录?我用过类似的东西
find . -type d -exec rmdir {} 2>/dev/null \;
但我需要运行多次才能删除仅包含空目录的目录。而且,它相当慢,尤其是在cygwin下。
答案1
结合 GNUfind
选项和谓词,此命令应该可以完成这项工作:
find . -type d -empty -delete
-type d
限制为目录-empty
限制为空-delete
删除每个目录
树是从叶子开始遍历的,不需要指定,-depth
因为它是由 暗示的-delete
。
答案2
首先列出深度嵌套的目录。
find . -depth -type d -exec rmdir {} \; 2>/dev/null
(请注意,重定向适用于find
整个命令,而不仅仅是rmdir
。仅重定向 forrmdir
会导致速度显着减慢,因为您需要调用中间 shell。)
您可以rmdir
通过传递谓词进行查找来避免在非空目录上运行-empty
。 GNU find 在即将运行该命令时会测试目录,因此将拾取刚刚清空的目录。
find . -depth -type d -empty -exec rmdir {} \;
另一种加速方法是将调用分组rmdir
。两者都可能比原始版本快得多,尤其是在 Cygwin 下。我预计这两者之间不会有太大区别。
find . -depth -type d -print0 | xargs -0 rmdir 2>/dev/null
find . -depth -type d -exec rmdir {} + 2>/dev/null
哪种方法更快取决于您有多少个非空目录。您不能结合-empty
使用方法进行分组调用,因为这样一来,仅包含空目录的目录在find
查看时就不是空的了。
另一种方法是运行多次传递。这是否更快取决于很多因素,包括整个目录层次结构是否可以在find
运行之间保留在磁盘缓存中。
while [ -n "$(find . -depth -type d -empty -print -exec rmdir {} +)" ]; do :; done
或者,使用 zsh。这全局限定符 F
匹配非空目录,因此/^F
匹配空目录。只包含空目录的目录不能那么容易匹配。
while rmdir **/*(/N^F); do :; done
(当rmdir
收到空命令行时,这将终止。)
答案3
find . -depth -type d -exec rmdir {} +
是这个问题最简单且符合标准的答案。
不幸的是,这里给出的其他答案都依赖于供应商特定的增强功能,而这些增强功能并非在所有系统上都存在。
答案4
我将这些别名用于常用find
命令,特别是当我使用以下命令清理磁盘空间时杜佩古鲁,其中删除重复项可能会导致出现大量空目录。
里面有评论,.bashrc
这样我以后需要调整时就不会忘记它们。
# find empty directories
alias find-empty='find . -type d -empty'
# fine empty/zero sized files
alias find-zero='find . -type f -empty'
# delete all empty directories!
alias find-empty-delete='find-empty -delete'
# delete empty directories when `-delete` option is not available.
# output null character (instead of newline) as separator. used together
# with `xargs -0`, will handle filenames with spaces and special chars.
alias find-empty-delete2='find-empty -print0 | xargs -0 rmdir -p'
# alternative version using `-exec` with `+`, similar to xargs.
# {}: path of current file
# +: {} is replaced with as many pathnames as possible for each invocation.
alias find-empty-delete3='find-empty -exec rmdir -p {} +'
# for removing zero sized files, we can't de-dupe them automatically
# since they are technically all the same, so they are typically left
# beind. this removes them if needed.
alias find-zero-delete='find-zero -delete'
alias find-zero-delete2='find-zero -print0 | xargs -0 rm'
alias find-zero-delete3='find-zero -exec rm {} +'