18

Suppose I have a dir tree like this:

ROOTDIR
    └--SUBDIR1
        └----SUBDIR2
            └----SUBDIR3

I am looking for a command such that when I input:

$ [unknown command] ROOTDIR

The whole dir tree can be deleted if there is no file but only dirs inside the whole tree. However, say if there is a file called hello.pdf under SUBDIR1:

ROOTDIR
    └--SUBDIR1
        └--hello.pdf
        └----SUBDIR2
            └----SUBDIR3

Then the command must only delete SUBDIR2 and below.

1

6 Answers 6

34
find ROOTDIR -type d -empty -delete

same as

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

but uses the built in "-delete" action.

Note that "-delete" implies "-depth".

3
  • Kudos for the most succinct answer by using find's own built-in delete! I am adding this to my local utilscripts! Commented Sep 19, 2014 at 2:26
  • Simplest, and the explanation about -delete implying -depth removes any lingering doubt. Thanks! Commented Feb 11, 2021 at 12:25
  • Not working on some BusyBox limited versions of find that don't include the -empty flag . Commented Mar 4 at 20:31
11

Alexis is close. What you need to do is this:

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

That will first drill down the directory tree until it finds the first empty directory, then delete it. Thus making the parent directory empty which will then be deleted, etc. This will produce the desired effect (I do this probably 10 times a week, so I'm pretty sure it's right). :-)

5
  • Why is -depth option necessary? find . -type d -empty -exec rmdir "{}" \; should also work.... right? Commented Nov 8, 2011 at 14:26
  • 4
    Consider if you have a tree (directories only) foo/bar/baz. Unless you use -depth, it will try to delete foo first, fail, and you'll end up with foo/bar after running. Commented Nov 8, 2011 at 14:43
  • 1
    Possibly alternative is to use + instead of ; so you batch remove directories. Since you're doing it depth-first the children will still be removed before the parents (possibly dependent on your version of rmdir/bash and reliant on rmdir not deleting nonempty directories). This works for me in bash on cygwin: mkdir -p a/b/c/d ; find a -depth -type d -exec rmdir {} + Commented Dec 19, 2013 at 23:05
  • 4
    People, go for go2null's much more succinct answer below! Can't understand why SE gives priority to accepted answers rather than answers with most upvotes in displaying the answers below the question. The OP accepts the best answer available at his time of choosing, but later on much better answers can come which the community upvotes, no? (Of course, this is something for meta...) Commented Sep 19, 2014 at 2:30
  • this does not work for me. it only deletes the deepmost leaf (SUBDIR3 in this case) Commented Oct 26, 2017 at 11:01
3

I would try this:

find ROOTDIR -type d -depth -exec rmdir {} \;
1

Here are some requirements before we can do it safely:

  1. remove subdirectories first and then upper level directories, i.e. we need to sort directory listing or use rmdir --parents flag
  2. start ROOTDIR always with / or ./ to avoid surprises with files beginning with -
  3. use NUL terminated list of directories to work with directory names with spaces

Here is how I'd do that in shell:

find ./ROOTDIR -type d | sort -r | tr '\n' '\000' | xargs -0 rmdir --ignore-fail-on-non-empty

If you don't mind some redundant errors then you can just force removing all directories with parents and you don't need to do any sorting (you can't sort NUL terminated strings which adds need to tr)

find ./ROOTDIR -type d -print0 | xargs -0 rmdir --ignore-fail-on-non-empty --parents
1
  • Kudos for the detailed explanation of your answer. I'd probably have used the same approach, until I learned about -empty -delete options to find in @go2null's answer. Commented Jul 8, 2019 at 17:10
0
rmdir $(find ROOTDIR -type d | sort -r)
2
  • 6
    This won't work if any of the directory names contains whitespace or globbing characters. It's generally a bad idea to use command substitution on a list of file names. It's especially a bad idea with find because find has a way to do the processing cleanly: find … -exec. Commented Nov 7, 2011 at 23:01
  • 1
    Thanks to Gilles for pointing that out. @lanzz, usually posting just a command without explaining what it does (and in this case, the pitfalls) is not enough. Please add to your answer. Commented Nov 8, 2011 at 3:06
0

I would do this:

find ROOTDIR -type d | xargs -0 -I {} rmdir {}

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.