288

Possible Duplicate:
How to remove all empty directories in a subtree?

I create directories very often, scattered over my home directory, and I find it very hard to locate and delete them.

I want any alias/function/script to find/locate and delete all empty directories in my home directory.

  • 5
    This does not answer your question, but could solve the underlying problem. I often use the construct: WORK=$(mktemp -d) or cd $(mktemp -d). Of course don't put important files that you need to preserve in those directories. But most likely your system is already setup to automagically make those files disappear after a while. – emory Aug 25 '12 at 23:35
  • I have my machine mount a tmpfs ram drive to the /z/ directory on start-up and do all my temporary work there. – Richard Oct 21 '13 at 20:23

2 Answers2

543

The find command is the primary tool for recursive file system operations. Use the -type d expression to tell find you're interested in finding directories only (and not plain files). The GNU version of find supports the -empty test, so

$ find . -type d -empty -print

will print all empty directories below your current directory.

Use find ~ -… or find "$HOME" -… to base the search on your home directory (if it isn't your current directory).

After you've verified that this is selecting the correct directories, use -delete to delete all matches:

$ find . -type d -empty -delete
Baldrick
  • 9,767
  • 2
  • 18
  • 8
  • 9
    Good solution, but it should be noted that not all version of find have -empty. – jordanm Aug 25 '12 at 21:49
  • @Baldrick Doesn't looks from home directory if I run it form ~/Desktop. – Santosh Kumar Aug 25 '12 at 21:58
  • @Santosh: The command as it is, is meant to be run from your home directory (that's why I added ~$ in the beginning). If you want to run it regardless of your working directory, use "$HOME" instead of . as jordanm suggested in his answer. – Baldrick Aug 25 '12 at 22:09
  • @jordanm: You're quit right, I edited my answer accordingly. – Baldrick Aug 25 '12 at 22:31
  • @Baldrick Just a last task. I want to escape my ~/project directory. – Santosh Kumar Aug 27 '12 at 06:12
  • @Santosh: You can use something like this: find "$HOME" -type d \! -path "$HOME/project/*" -empty -delete. The ! operator (or the escaped \!) returns false if the following expression is true. In effect, it excludes the ~/project directory. Note that if ~/project is empty, it will be deleted. – Baldrick Aug 28 '12 at 08:07
  • 4
    Consider changing the second example to . instead of ~. If somebody copy-pastes this without noticing and only checks the output of the first this can have bad consequences. – Florian Wendelborn Jun 03 '16 at 01:28
  • 5
    I would add -mindepth 1 here, to prevent from deleting the starting directory itself, if it would be empty. It's not really probable case for $HOME but if you would use this on any other directory.. – Greg Dubicki Aug 20 '16 at 12:46
  • I had to use $ find . -type d -empty -delete – KingsInnerSoul Oct 10 '16 at 14:49
  • @KingsInnerSoul Wasn't that already mentioned in answer? – Franklin Yu Nov 03 '17 at 18:22
  • Maybe you are new to SE, but you can see that the my comment was added on October, and the answer was edited in November to include it! There is no need to spam everyone over a year after it was answered! – KingsInnerSoul Nov 05 '17 at 01:44
  • It seems that it doesn't see hidden files. How to do it ? – Charaf Sep 01 '18 at 01:32
  • BSD version under macOS 10.12 has -empty. – Hotschke Oct 29 '18 at 10:46
25

You can call rmdir on every directory, since rmdir will only delete a directory if it is empty:

find "$HOME" -type d -exec rmdir {} + 2>/dev/null

If you also want to print the directories being removed, you will need to check if they are empty:

find "$HOME" -type d -exec bash -c 'shopt -s nullglob; shopt -s dotglob; files=("$1"/*); [[ ${files[@]} ]] || rmdir -v "$1"' -- {} \; 

Here is a pure bash example (version 4 or higher):

shopt -s globstar
for dir in **/; do
   files=("$dir"/*)
   [[ ${files[@]} ]] || rmdir -v "$dir"
done
jordanm
  • 42,678
  • And what if I only want to find/locate and not delete? – Santosh Kumar Aug 25 '12 at 21:44
  • @Santosh - In either of the last two examples, just change rmdir -v to echo. – jordanm Aug 25 '12 at 21:47
  • 8
    BusyBox find doesn't have -empty, so the -exec trick is helpful. But rather than sending errors off to /dev/null, it's better to tell rmdir to suppress them, e.g. find . -type d -depth -exec rmdir -p --ignore-fail-on-non-empty {} \; – Robert Calhoun Apr 01 '15 at 19:19
  • 1
    These commands have terrible performance since they create a new process for every directory found. When using that approach, you really should at least use something like find ... | xargs -n 100 rmdir to delete them in batches. Even then, it won't work properly because it will fail to remove early directories that will later become empty because of later empty directories' removal. Thus you'd need to execute it several times. – jlh Nov 13 '15 at 13:25
  • 4
    @jlh No, the first command will only execute rmdir once. That's the difference between using + and \; for terminating a command in find. – jordanm Nov 13 '15 at 14:10