Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

How can I remove all empty directories in a subtree? I used something like

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

but I needs to be run multiple times in order to remove directories containing empty directories only. Moreover, it's quite slow, especially under cygwin.

share|improve this question

3 Answers 3

up vote 20 down vote accepted

List the directories deeply-nested-first.

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

(Note that the redirection applies to the find command as a whole, not just to rmdir. Redirecting only for rmdir would cause a significant slowdown as you'd need to invoke an intermediate shell.)

You can avoid running rmdir on non-empty directories by passing the -empty predicate to find. GNU find tests the directory when it's about to run the command, so directories that have just been emptied will be picked up.

find . -depth -type d -empty -exec rmdir {} \;

Another way to speed up would be to group the rmdir invocations. Both are likely to be noticeably faster than the original, especially under Cygwin. I don't expect much difference between these two.

find . -depth -type d -print0 | xargs -0 rmdir 2>/dev/null
find . -depth -type d -exec rmdir {} + 2>/dev/null

Which method is faster depends on how many non-empty directories you have. You can't combine -empty with methods for grouping invocations, because then the directories that only contain empty directories aren't empty by the time find looks at them.

Another method would be to run multiple passes. Whether this is faster depends on a lot of things, including whether the whole directory hierarchy can remain in the disk cache between find runs.

while [ -n "$(find . -depth -type d -empty -print -exec rmdir {} +)" ]; do :; done

Alternatively, use zsh. The glob qualifier F matches non-empty directories, so /^F matches empty directories. Directories that only contain empty directories can't be matched so easily.

while rmdir **/*(/N^F); do :; done

(This terminates when rmdir receives an empty command line.)

share|improve this answer
    
That's it. Instead of 90 seconds it takes 0.90 s. –  maaartinus Mar 1 '11 at 22:14
    
@maaartinus: I'm curious: do you have a similar data set where you could try without -p? I wouldn't have thought it would make a difference. –  Gilles Mar 1 '11 at 22:15
1  
@maartinus — other little optimizations: adding -empty should work with this one (although I'm not sure exactly how much it'll gain). And very, very trivially, since you probably don't want to remove ., use -mindepth 1. –  mattdm Mar 1 '11 at 22:19
    
It was not the removal but the process start up overhead, what took nearly all the time. I had overlooked the -depth argument, which makes rmdir -p useless. I've changed my comment already. The 90 s was my original attempt; there's nothing surprising here. –  maaartinus Mar 1 '11 at 22:20
1  
I realized we can remove the rmdir command call altogether, at least with GNU find, with this command: find . -depth -type d -empty -delete –  Christophe Drevet Jan 2 at 14:26

If you just tack a -p on your rmdir, that'll work in one pass. It won't be pretty or optimal, but it should get everything. That tells rmdir to remove any non-empty parent directories of the one you're removing.

You can save a little bit by adding the -empty test to find, so it doesn't bother with non-empty directories.

share|improve this answer

Combining GNU find options and predicates, this command should do the job:

find . -type d -empty -delete
  • -type d restricts to directories
  • -empty restricts to empty ones
  • -delete removes each directory

The tree is walked from the leaves without the need to specify -depth as it is implied by -delete.

share|improve this answer
1  
-delete already implies -depth so you don't need to specify that manually. –  jamadagni Sep 19 at 2:31
    
Thanks, I didn't realize that. Answer updated. –  Christophe Drevet Sep 19 at 15:57

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.