Finding empty directories

BashUnixDirectory

Bash Problem Overview


I need to find empty directories for a given list of directories. Some directories have directories inside it.

If inside directories are also empty I can say main directory is empty otherwise it's not empty.

How can I test this?

For example:

A>A1(file1),A2 this is not empty beacuse of file1
B>B1(no file) this is empty
C>C1,C2 this is empty

Bash Solutions


Solution 1 - Bash

It depends a little on what you want to do with the empty directories. I use the command below when I wish to delete all empty directories within a tree, say test directory.

find test -depth -empty -delete

One thing to notice about the command above is that it will also remove empty files, so use the -type d option to avoid that.

find test -depth -type d -empty -delete

Drop -delete to see the files and directories matched.

If your definition of an empty directory tree is that it contains no files then you be able to stick something together based on whether find test -type f returns anything.

find is a great utility, and RTFM early and often to really understand how much it can do :-)

Solution 2 - Bash

You can use the following command:

find . -type d -empty

Solution 3 - Bash

Check whether find <dir> -type f outputs anything. Here's an example:

for dir in A B C; do
    [ -z "`find $dir -type f`" ] && echo "$dir is empty"
done

Solution 4 - Bash

find directory -mindepth 1 -type d -empty -delete

This is the version that I found most interesting. If executed from inside directory, it will delete all empty directories below (a directory is considered empty if it only contains empty directories).

The mindepth option prevents the directory itself from being deleted if it happens to be empty.

Solution 5 - Bash

find . -type d -empty

finds and lists empty directories and sub-directories in the current tree. E.g. resulting list of empty dirs and subdirs:

./2047
./2032
./2049
./2063
./NRCP26LUCcct1/2039
./NRCP26LUCcct1/2054
./NRCP26LUCcct1/2075
./NRCP26LUCcct1/2070

No operation is made on the directories. They are simply listed. This works for me.

Solution 6 - Bash

Just find empty dirs

In order to just find empty directories (as specified in the question title), the mosg's answer is correct:

find -type d -empty

But -empty may not be available on very old find versions (this is the case of HP-UX for example). If this is your case, see the techniques described in below section Is a directory empty?.

Delete empty dirs

This is a bit tricky: Suppose a directory MyDir contains empty directories. After removing these empty directories, MyDir will become an empty directory and should also be removed. Therefore I use the command rmdir with the option --parents (or -p) that also removes parent directories when possible:

find -type d -empty -exec rmdir -vp --ignore-fail-on-non-empty {} +

On older find version the statement + is not yet supported, therefore you may use ; instead:

find -type d -empty -exec rmdir -vp --ignore-fail-on-non-empty {} `;`

Is a directory empty?

Most of these answers explain how to check if a directory is empty. Therefore I provide here the three different techniques I know:

  1. [ $(find your/dir -prune -empty) = your/dir ]

     d=your/dir
     if [ x$(find "$d" -prune -empty) = x"$d" ]
     then
       echo "empty (directory or file)"
     else
       echo "contains files (or does not exist)"
     fi
    

a variation:

    d=your/dir
    if [ x$(find "$d" -prune -empty -type d) = x"$d" ]
    then
      echo "empty directory"
    else
      echo "contains files (or does not exist or is not a directory)"
    fi

Explanation:

  • find -prune is similar than find -maxdepth 0 using less characters

  • find -type d prints directories only

  • find -empty prints the empty directories and files

          > mkdir -v empty1 empty2 not_empty
          mkdir: created directory 'empty1'
          mkdir: created directory 'empty2'
          mkdir: created directory 'not_empty'
          > touch not_empty/file
          > find empty1 empty2 not_empty -prune -empty
          empty1
          empty2
    
  1. (( ${#files} ))

This trick is 100% bash but invokes (spawns) a sub-shell. The idea is from Bruno De Fraine and improved by teambob's comment. I advice this one if you use [tag:bash] and if your script does not have to be portable.

    files=$(shopt -s nullglob dotglob; echo your/dir/*)
    if (( ${#files} ))
    then 
      echo "contains files"
    else 
      echo "empty (or does not exist or is a file)"
    fi

Note: no difference between an empty directory and a non-existing one (and even when the provided path is a file).

  1. [ $(ls -A your/dir) ]

This trick is inspired from nixCraft's article posted in 2007. Andrew Taylor answered in 2008 and gr8can8dian in 2011.

    if [ "$(ls -A your/dir)" ]
    then
      echo "contains files"
    else
      echo "empty (or does not exist or is a file)"
    fi

or the one-line bashism version:

    [[ "$(ls -A your/dir)" ]] && echo "contains files" || echo "empty or ..."

Note: ls returns $?=2 when the directory does not exist. But no difference between a file and an empty directory.

Solution 7 - Bash

How about rmdir *? That command will fail on non-empty directories.

Solution 8 - Bash

This recursive function would seem to do the trick:

# Bash
findempty() {
    find ${1:-.} -mindepth 1 -maxdepth 1 -type d | while read -r dir
    do
        if [[ -z "$(find "$dir" -mindepth 1 -type f)" ]] >/dev/null
        then
            findempty "$dir"
            echo "$dir"
        fi
    done
}

Given this example directory structure:

.
|-- dir1/
|-- dir2/
|   .
|-- dir1/
|-- dir2/
|   -- dirB/     |-- dir3/     |   -- dirC/
|       -- file5     |-- dir4/     |   |-- dirD/     |   -- file4
-- dir5/         -- dirE/
`-- dir_V/
-- dirC/
|       .
|-- dir1/
|-- dir2/
|   .
|-- dir1/
|-- dir2/
|   -- dirB/     |-- dir3/     |   -- dirC/
|       -- file5     |-- dir4/     |   |-- dirD/     |   -- file4
-- dir5/         -- dirE/
`-- dir_V/
-- dirC/
|       -- file5     |-- dir4/     |   |-- dirD/     |   -- file4
-- dir5/         -- dirE/
`-- dir_V/
-- file4
.
|-- dir1/
|-- dir2/
|   .
|-- dir1/
|-- dir2/
|   -- dirB/     |-- dir3/     |   -- dirC/
|       -- file5     |-- dir4/     |   |-- dirD/     |   -- file4
-- dir5/         -- dirE/
`-- dir_V/
-- dirC/
|       .
|-- dir1/
|-- dir2/
|   .
|-- dir1/
|-- dir2/
|   -- dirB/     |-- dir3/     |   -- dirC/
|       -- file5     |-- dir4/     |   |-- dirD/     |   -- file4
-- dir5/         -- dirE/
`-- dir_V/
-- dirC/
|       -- file5     |-- dir4/     |   |-- dirD/     |   -- file4
-- dir5/         -- dirE/
`-- dir_V/
-- file4
-- dir5/         -- dirE/
`-- dir_V/
-- dirE/
`-- dir_V/

The result of running that function would be:

./dir1
./dir5/dirE/dir_V
./dir5/dirE
./dir5
./dir2/dirB
./dir2

which misses /dir4/dirD. If you move the recursive call findempty "$dir" after the fi, the function will include that directory in its results.

Solution 9 - Bash

The following command returns 1 if a directory is empty (or does not exists) and 0 otherwise (so it is possible to invert the return code with ! in a shell script):

find $dir -type d -prune -empty -exec false {} +

Solution 10 - Bash

I created a simple structure as follows:

test/
test/test2/
test/test2/test2.2/
test/test3/
test/test3/file

The test/test3/file contains some junk text.

Issuing find test -empty returns "test/test2/test2.2" as the only empty directory.

Solution 11 - Bash

a simple approach would be,

$ [ "$(ls -A /path/to/direcory)" ] && echo "not empty" || echo "its empty"

also,

if [ "$(ls -A /path/to/direcory)" ]; then
   echo "its not empty"
else 
   echo "empty directory"

Solution 12 - Bash

find . -name -type d -ls |awk '($2==0){print $11}'

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionsoFieldView Question on Stackoverflow
Solution 1 - BashMartinView Answer on Stackoverflow
Solution 2 - BashmosgView Answer on Stackoverflow
Solution 3 - BashMarcelo CantosView Answer on Stackoverflow
Solution 4 - BashSO StinksView Answer on Stackoverflow
Solution 5 - Bashuser7194913View Answer on Stackoverflow
Solution 6 - BashoHoView Answer on Stackoverflow
Solution 7 - BashevandrixView Answer on Stackoverflow
Solution 8 - BashDennis WilliamsonView Answer on Stackoverflow
Solution 9 - BashMateusz PiotrowskiView Answer on Stackoverflow
Solution 10 - BashJames SumnersView Answer on Stackoverflow
Solution 11 - Bashphoenix24View Answer on Stackoverflow
Solution 12 - BashVijayView Answer on Stackoverflow