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