如何删除子树中的所有空目录?


Answers:


221

结合GNU find选项和谓词,此命令应完成以下工作:

find . -type d -empty -delete
  • -type d 限制目录
  • -empty 限制为空的
  • -delete 删除每个目录

这棵树是从树叶上走-depth下来的,不需要指定,因为暗示了-delete


2
-delete已经暗示,-depth因此您无需手动指定。
jamadagni 2014年

1
谢谢,我没有意识到。答案已更新。
Christophe Drevet-Droguet 2014年

11
我将在-mindepth 1此处添加内容,以防止删除起始目录本身(如果该目录为空)。
格雷格·杜比奇

2
很好,但是在我的旧SunOS主机上不起作用...
dokaspar

2
!对外壳有特殊的含义。您需要逃脱它。像这样:\! -name 'Completed'之前-delete应该工作。或者,您只需将标记文件放在此目录中。
Christophe Drevet-Droguet '18

53

列出目录,最先嵌套。

find . -depth -type d -exec rmdir {} \; 2>/dev/null

(请注意,重定向不仅适用于整个find命令,还适用于整个命令rmdir。仅针对进行重定向rmdir会导致运行速度显着下降,因为您需要调用中间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收到空命令行时终止。)


而已。耗时0.9秒,而不是90秒。
maaartinus

@maaartinus:我很好奇:您是否有类似的数据集可以尝试-p?我不会想到这会有所作为。
Gilles

3
@maartinus —其他一些小的优化:添加-empty应该可以与此(尽管我不确定确切会获得多少)一起使用。而且非常非常琐碎,因为您可能不想删除.,使用-mindepth 1
mattdm 2011年

并不是所有的时间都花在了搬迁上,而是花在了启动上。我忽略了这一-depth论点,这rmdir -p毫无用处。我已经更改了我的评论。90年代是我最初的尝试;这里没有什么奇怪的。
maaartinus 2011年

2
我意识到我们可以使用以下rmdir命令完全删除命令调用,至少使用GNU find:find . -depth -type d -empty -delete
Christophe Drevet-Droguet 2014年

6

如果您仅对a -p进行操作rmdir,那将一次性完成。它不会是漂亮的或最佳的,但是它应该可以得到所有。这告诉rmdir删除要删除的目录的所有非空父目录。

您可以通过添加-empty测试来节省一点时间,因此它不会打扰非空目录。


3

find . -depth -type d -exec rmdir {} +

是对此问题最简单且符合标准的答案。

不幸的是,此处给出的其他答案都取决于并非所有系统上都存在的特定于供应商的增强功能。


3
对于每个无法删除的目录,此答案都会引发一个错误,该错误可能不那么理想。
Willem van Ketwich'4

0

find . -type d -printf "%d %p\n" |\ sort -nr |\ perl -pe 's/^\d+\s//;' |\ while read dir; do \ (rmdir "$dir" > /dev/null 2>&1); \ done

运作方式如下:

  1. 递归列出所有目录及其深度
  2. 按其深度的降序排序
  3. 仅过滤目录路径
  4. 运行rmdir由一个列表中的一个上

0

我将这些别名用于常用find命令,尤其是当我使用dupeguru清理磁盘空间时,删除重复项可能会导致很多空目录。

内部注释,.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 {} +'

-2

rm -r */命令对我来说很容易工作。rm应该要求-f强制删除包含文件的目录。rm -r应该只删除空目录。我很乐意为什么这可能是错误的。这也应该留下文件,因为*/仅查看文件夹。


1
我强烈建议首先进行彻底测试,因为rm这主要是为了删除文件。虽然*/只匹配目录,但我不知道它在更深层次上的作用。我也可以想象它仅在某些系统上有效。
maaartinus
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.