April 29, 2009, 2:53 PM — As you undoubtedly know, the rmdir command will remove an empty directory but, if a directory contains files, it will balk and report "Directory not empty". To remove directories which are in fact empty is then easy. In any file system containing multiple directories, you can issue the "rmdir *" command knowing that only the empty directories will be removed.
To recursively remove empty directories, you could try a mix of the find and rmdir commands. For example, this command would remove numerous directories yet leave all the populated ones:
find . -type d -print | xargs rmdir
If you don't want to see all the "Directory not empty" errors, you can send standard error to /dev/null:
find . -type d -print | xargs rmdir 2>/dev/null
Looking for directories with find and then removing them has one drawback, however, If a directory becomes empty in the process of removing a directory that's inside of it, the parent directory will not be removed because find will detect it before it finds its child directory and it won't yet be empty.
You could run one of the commands shown above multiple times, maybe until no more "Directory not empty" errors appear. Alternatively, you could run a script like this one that uses find to create a list of directories, reverses the list so that child directories appear before their parents and then runs a rmdir against each directory in the list. In this way, all of the empty directories are removed in one pass.
#!/bin/bash # get directory list find . -type d -print > dirs$$ # reverse the listing tail -r dirs$$ > revdirs$$ while read dirname do rmdir $dirname 2>/dev/null done < revdirs$$ # clean up rm dirs$$ rm revdirs$$
One of the core commands in this script is the tail -r command. This command reverses the contents of a file or of any input piped to it. In fact, this command is so useful for this operation that you could reduce the script above to this one-liner:
find . -type d | tail -r | xargs rmdir
Or, again, if you don't want to see all the "Directory not empty" complaints, pipe the error output of this string of commands to /dev/null:
find . -type d | tail -r | xargs rmdir 2>/dev/null
As a one-liner, this command lends itself to use as an alias.
$ alias rmEmptyDirs="find . -type d | tail -r | xargs rmdir 2>/dev/null"
If you want to test this alias, create a directory under /tmp and populate it with a series of new directories. The easiest way to do this is to use the mkdir -p command:
cd /tmp/testing mkdir -p a/b/c/d/e/f/g/h/i/j mkdir -p d/r/a/g/o/n/f/l/y mkdir -p d/i/t/c/h mkdir x mkdir y mkdir z
Then touch a file somewhere in the newly created directory structure:
If you then run the rmEmptyDirs alias, you will find that only the a, a/b and a/b/c directories and the file "myfile" remain.
The mkdir -p command, which creates a directory structure by creating all the directories along the requested path that don't already exist, has a partner in rmdir -p that removes all the directories along the way, provided they are empty. This leads to a further simplification of our alias. Now we can reduce it to this:
alias rmEmptyDirs="find . -type d | xargs rmdir -p"
alias rmEmptyDirs="find . -type d | xargs rmdir -p" 2>/dev/null
Using rmdir -p, the list reversing operation is no longer needed. If you don't suppress standard error, you will note that this command will refuse to remove directories that it finds until it reaches one that is empty. At that point, it will remove all of its empty parents and grandparents.
Another simplication is to use the rmdir command's -s option to suppress the error output instead of piping it to /dev/null. Now, we have the ultimately simply command for removing empty directories:
alias rmEmptyDirs="find . -type d | xargs rmdir -ps"
You can't make the process much easier than that! Our original rmdir command with a couple command options only has to be run once and gets rid of all empty directories in its path.