123

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
codeforester
  • 39,467
  • 16
  • 112
  • 140
soField
  • 2,536
  • 9
  • 36
  • 44

12 Answers12

310

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 :-)

ssc
  • 9,528
  • 10
  • 64
  • 94
Martin
  • 5,119
  • 3
  • 18
  • 16
  • 9
    -delete implies -depth (at least for GNU findutils 4.4.2) – SO Stinks Jun 13 '11 at 13:30
  • 5
    did not know about `-empty`, so convenient! – Raffi Nov 02 '15 at 14:33
  • 2
    However on machine that are not the latest and greatest linux. (EG Solaris), then you have no fancy find features like -empty or -delete. – anthony Feb 03 '16 at 01:18
  • @antofthy been a while since I touched Solaris, but you used to have a choice between Sun's own version and the GNU version of various utilities. GNU tools was prefixed with g so perhaps gfind might work – Martin Feb 03 '16 at 10:33
  • 9
    On MacOS-X, for ***almost*** empty directories, run `find test -name ".DS_Store" -delete` first, then the `-empty delete` command. Also note, like to `pushd` to the parent directory, so that `find test` becomes `find .`, but the rest of the commands are the same. – Olie Mar 22 '16 at 16:41
  • 1
    @Martin Can you please add the definition of `-depth` here i.e. *Cause find to perform a depth-first traversal, i.e., directories are visited in post-order and all entries in a directory will acted on before the directory itself.* I think it is relevant here. – Léo Léopold Hertz 준영 Apr 23 '16 at 11:13
  • You can mix actions as well, such as adding and -ls or -print "find . -depth -type d -empty -ls -delete" – hpavc Jul 03 '18 at 22:27
  • @LéoLéopoldHertz준영,what's the difference between add -depth or not in this question? – kittygirl Jan 05 '19 at 09:43
  • 2
    Be careful in what order you use `-delete` and `-type d` with `-o` unless you want to loose a few hours googling `ext4magic` and loose a few gigs of data still to be backed up. – myol Nov 23 '20 at 05:35
79

You can use the following command:

find . -type d -empty
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
mosg
  • 12,041
  • 12
  • 65
  • 87
  • 1
    -empty only works if the current directory is completely empty, not if the subtree contains no files. – Marcelo Cantos May 11 '10 at 13:09
  • @soField Tested *find . -type d -empty* with FreeBSD & CentOS. Works fine. What your OS? – mosg May 11 '10 at 13:22
  • 1
    hp-ux so there is no empty parameter – soField May 11 '10 at 13:47
  • @soField So, you see, that it's better (for all of us) to post this data at the top of your question... – mosg May 11 '10 at 14:00
  • 2
    find doesn't have -empty on solaris either, but it does have -depth to enforce depth-first traversal so that empty subdirectories can be deleted before the parent directory is checked for emptiness. – eirikma Mar 24 '11 at 23:34
  • hp-ux curreltny is completly exotic system, usually based on intel itanium cpu. try find GNU tools with its find command. – Znik Apr 16 '18 at 12:35
35

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
Nick Heiner
  • 119,074
  • 188
  • 476
  • 699
Marcelo Cantos
  • 181,030
  • 38
  • 327
  • 365
  • 2
    No, it will not output subdirectories. That's what the `-type f` is for. – Marcelo Cantos May 11 '10 at 13:09
  • Howerver if there are *empty files*, your solution won't yield the message. – YasirA May 11 '10 at 13:39
  • 4
    Yasir: I would think that a directory containing an empty file wound not be empty itself. Would that not be the correct result? – Ukko May 11 '10 at 14:59
  • 2
    @akostadinov: If I create the directories and files as indicated by the OP — `mkdir A B C A/A1 A/A2 B/B1 C/C1 C/C2; touch A/A1/file1` — and run the code in my answer, it reports that B and C are empty, as required by the OP. So you will need to be a little more specific than, "it wont work". – Marcelo Cantos Sep 19 '13 at 12:51
  • @MarceloCantos, I said everything needed to reproduce. Having your script work with some example data, does not prove it correct in all corner cases... or course I'm not telling this could be a problem for the OP's use case. – akostadinov Sep 19 '13 at 18:55
  • In the example, B1, C1, and C2 are empty directories for `$dir` values B and C, and it clearly works for them. I'm not saying you're wrong — there possibly is a bug in my code — but it most certainly isn't clear from your comments what the problem is. Perhaps you could supply an example that fails. – Marcelo Cantos Sep 20 '13 at 22:37
  • @akostadinov: I just noticed that I didn't address the above response to you, so here's a ping. – Marcelo Cantos Mar 24 '14 at 02:34
  • @MarceloCantos, looks like I misread the question. It's very ugly lacking punctuation... sorry for confusion. I think your answer is nice. – akostadinov Mar 24 '14 at 16:19
  • 1
    If you are a Bash noob like me, check what -z means [here](http://stackoverflow.com/questions/18096670/what-does-z-mean-in-bash). – OmarOthman Apr 14 '17 at 14:54
  • the -z question is answered here: https://stackoverflow.com/questions/18096670/what-does-z-mean-in-bash – sk8asd123 Nov 10 '22 at 16:43
28
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.

SO Stinks
  • 3,258
  • 4
  • 32
  • 37
  • 2
    You can follow this up with `rmdir --ignore-fail-on-non-empty -p directory` to get rid of the parents as well. – Pete Peterson Dec 22 '11 at 15:29
  • @Pete Peterson My command seems to remove directories that only contain other empty directories (which is what OP also seems to want). I note that your command will usually leave the user in a directory with a missing i-node even if they accomplish what they want, which may be confusing to them. Maybe I'm missing the point. – SO Stinks Aug 07 '15 at 12:48
24

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.

Dan D.
  • 73,243
  • 15
  • 104
  • 123
user7194913
  • 410
  • 4
  • 5
17

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
      
  2. (( ${#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 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).

  3. [ $(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.

Community
  • 1
  • 1
oHo
  • 51,447
  • 27
  • 165
  • 200
  • `rmdir -vp` helped me immensely since I needed to not just delete all empty dirs under a root, but check for empty dirs and parent dirs after deleting a file. In my situation empty dirs are fine as long as they are not in the tree i'm currently removing a file from. Thanks! – Ethan Hohensee Mar 07 '19 at 16:56
3

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

evandrix
  • 6,041
  • 4
  • 27
  • 38
  • Something I have done at times, for general clean up. Also done things like `rmdir */*/* */* *` Though that does not handle 'dot-files' but then in manual situations (cleaning data files) you generally don't expect 'dot-files'. The recursive methods, however are for more automated general clean up, especially in very large directory structures. – anthony Feb 04 '16 at 23:30
  • In one case was more complicated as I needed to remove empty directories where 'empty' included directories that could contain a single 'readme' file. Anything else in the directory and it wasn't 'empty'. In that example the directory structure involved tens of thousands of sub-directories. – anthony Feb 04 '16 at 23:38
2

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/
    |   `-- dirB/
    |-- dir3/
    |   `-- dirC/
    |       `-- file5
    |-- dir4/
    |   |-- dirD/
    |   `-- file4
    `-- dir5/
        `-- 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.

Dennis Williamson
  • 346,391
  • 90
  • 374
  • 439
1

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 {} +
Mateusz Piotrowski
  • 8,029
  • 10
  • 53
  • 79
0

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.

James Sumners
  • 14,485
  • 10
  • 59
  • 77
0

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"
phoenix24
  • 2,072
  • 2
  • 20
  • 24
0
find . -name -type d -ls |awk '($2==0){print $11}'
Vijay
  • 65,327
  • 90
  • 227
  • 319