Thursday, March 5, 2009

Test for empty directory - bash scripting


Lets see how we can check whether a directory is empty or not in bash scripting.

#Create a directory
$ mkdir testdir

#Usual way to check if a directory is empty or not
$ [ -z $(ls testdir/) ] && echo "empty" || echo "NOT"
empty

#Lets create a file in testdir
$ touch testdir/file1

#Oh, it works, great
$ [ -z $(ls testdir/) ] && echo "empty" || echo "NOT"
NOT

#Create one more file, file2
$ touch testdir/file2

#Now see, ohh!!! it has faced some problem
$ [ -z $(ls testdir/) ] && echo "empty" || echo "NOT"
-bash: [: file1: binary operator expected
NOT

#Solution to the above:
$ [ -z "$(ls testdir/)" ] && echo "empty" || echo "NOT"
NOT

#Clear the testdir
$ rm testdir/file*

#So that
$ [ -z "$(ls testdir/)" ] && echo "empty" || echo "NOT"
empty

#Create a hidden file in the testdir
$ touch testdir/.hden

#But the above test condition is not going to take account of hidden files (as we are doing only ls)
$ [ -z "$(ls testdir/)" ] && echo "empty" || echo "NOT"
empty

#So use -A (do not list implied . and ..) option with ls
$ [ -z "$(ls -A testdir/)" ] && echo "empty" || echo "NOT"
NOT

#Create a file
$ touch testdir/file1

#Working ...
$ [ -z "$(ls -A testdir/)" ] && echo "empty" || echo "NOT"
NOT

#Remove the files (including hidden file) from testdir
$ rm testdir/.hden ; rm testdir/file1

#So the above is working.
$ [ -z "$(ls -A testdir/)" ] && echo "empty" || echo "NOT"
empty

But if we use -a option instead of -A
$ [ -z "$(ls -a testdir/)" ] && echo "empty" || echo "NOT"
NOT

This is because:

$ ls -a testdir/
. ..

But
$ ls -A testdir/

-A do not list implied . and ..

If you have any other way, feel free to post a comment. Thanks

2 comments:

rattus said...

http://wooledge.org:8000/BashFAQ/004 has some more.

Karan Bohra said...

You should also check that "testdir" is really a directory and is readable by the user, otherwise be prepared for getting false positive results.

[ -d "$1" ] && \
[ -r "$1" ] && \
n=$(ls -A -- "$1") && \
[ -z "$n" ] && echo "'$1' empty" || echo "'$1' nonempty"

Another way is (assuming not very many files that we have a argument too long error)

[ -d "$1" ] && [ -r "$1" ] && cd -- "$1";
IFS=" ";
set X * [*] .[!.]* '.[!.]*' .[.]?*; shift
case $* in
'* [*] .[!.]* .[!.]* .[.]?*' ) echo "'$1' empty";;
* ) echo "'$1' nonempty";;
esac

© Jadu Saikia www.UNIXCL.com