Find empty dirs 

*Tags*: cmd:find

Newsgroups:  comp.unix.shell
Date:        26 Nov 2006 21:51:03 -0800
> Is there any way to find which dir (under cwd) is empty? I.e., has no
> file in it but may have sub dirs?

Here is one way. Note that this is breaks if there are paths with spaces in them:

find . -type d -exec sh -c '[ -z "$(find '{}' -maxdepth 1 ! -type d -print)" ]' \; -print

Kaz Kylheku

Find empty dirs 

> Note that this is breaks if there are paths with
> spaces in them.
$ find . -type d -exec sh -c '[ -z "$(find '{}' -maxdepth 1 ! -type d -print)" ]' \; -print
find: ./af/empty: No such file or directory
find: dir: No such file or directory
./af/empty dir
$ find . -type d -exec sh -c '[ -z "$(find '\''{}'\'' -maxdepth 1 ! -type d -print)" ]' \; -print
./af/empty dir
./af/empty dir/subd
$ find . -type d -exec sh -c '[ -z "$(find "'{}'" -maxdepth 1 ! -type d -print)" ]' \; -print
./af/empty dir
./af/empty dir/subd

T

Find empty dirs 

> > Here is one way. Note that this is breaks if there are paths with
> > spaces in them:
> >
> > find . -type d -exec sh -c '[ -z "$(find '{}' -maxdepth 1 ! -type d
> > -print)" ]' \; -print
>
> Thanks, that works.
>
> May I know why it will break when there are spaces in path name?
>
> find: ./af/empty: No such file or directory
> find: dir: No such file or directory
> ./af/empty dir
>
> I saw that the {} has been quoted with ''. Why is the quote ignored?

That's a mistake. Note that the entire argument to sh -c is in single quotes. So these inner quotes break that up into two single-quoted pieces with {} in the middle. It doesn't matter if you remove these; either way, it breaks.

To fix the problem, you have to get {} to be quoted. Here is how. Switch to double quotes, and then escape them within. Command expansion takes place now so you have to escape that too, you want the embedded sh -c to evaluate the $(find …), not the outer command:

find . -type d -exec sh -c "[ -z \"\$(find \"{}\" -maxdepth 1 ! -type d -print)\" ]" \; -print

The real challenge would be protecting this against expansions of {} which look like a predicate, valid or otherwise.

Kaz Kylheku

Find empty dirs 

> To fix the problem, you have to get {} to be quoted. Here is how.
> Switch to double quotes, and then escape them within. Command expansion
> takes place now so you have to escape that too, you want the embedded
> sh -c to evaluate the $(find ...), not the outer command:
>
> find . -type d -exec sh -c "[ -z \"\$(find \"{}\" -maxdepth 1 ! -type d
> -print)\" ]" \; -print

Hi, thank you Kaz for the detailed explanation.

FYI, I found the following sufficient enough under Linux, in which sh is actually bash:

$ find . -type d -exec sh -c '[ -z "$(find "'{}'" -maxdepth 1 ! -type d -print)" ]' \; -print
./af/empty dir
./af/empty dir/subd