Although there are many reasonable solutions here, I am personally not a big fan of most of these answers, as many return a lot of output when returning directory contents. I was expecting a solution that would better handle directories with large numbers of files, while also one that I think is easy to understand.
So, this is what I ended up with, and thought I would share:
This appears to work OK for me on RedHat:
dir="/tmp/my_empty_dir"
[[ -d "${dir}" && -z "$(find "${dir}" -not -path "${dir}" -print -quit)" ]] && echo "${dir} is empty"
In this example:
First ensure dir exists -d "$dir"
, otherwise this will return empty (we will also see an error sent to stderr).
However it's likely you would need to test for this separately, as a "not empty" result is likely to mean "contains files" (which is not correct)
AND
Find: (find $dir -not -path $dir -print -quit
):
- Find everything in $dir
- Exclude the directory $dir from the resulting output
- Print the first result (something else within $dir)
- Quit immediately (only return the first result).
BEWARE the -path parameter takes a "pattern", so if you are expecting special characters (eg: *, [, ]) these would need to be escaped Eg:
dir='/tmp/test[dir]'
dirpath='/tmp/test\[dir\]'
find "${dir}" -not -path "${dirpath}" -print -quit
During my test, this also successfully found hidden files. ($dir/.hidden
)
Find returns 0 regardless of whether anything is found, and I don't currently see a simpler way to test this, so:
As per other examples I also wrapped this in:
Empty: [[ -z "$result" ]]
to test if the result is blank.
NOT Empty: [[ ! -z "$result" ]]
to test if the result is not blank.
Yes, the braces around ${dir} are not really required, but I thought it best to help handle this use case
dir="/tmp/"
[[ -d "${dir}subdir" ...
[[ ! -d "$dir" ]] || [[ -z `ls -A "$dir"` ]] || echo "$dir exists and isn't empty"