I want to test if a directory doesn't contain any files. If so, I will skip some processing.
I tried the following:
if [ ./* == "./*" ]; then
echo "No new file"
exit 1
fi
That gives the following error:
line 1: [: too many arguments
Is there a solution/alternative?
26 Answers
if [ -z "$(ls -A /path/to/dir)" ]; then
echo "Empty"
else
echo "Not Empty"
fi
Also, it would be cool to check if the directory exists before.
ls -A means list all but . or ..
No need for counting anything or shell globs. You can also use read in combination with find. If find's output is empty, you'll return false:
if find /some/dir -mindepth 1 -maxdepth 1 | read; then
echo "dir not empty"
else
echo "dir empty"
fi
This should be portable.
if [ -n "$(find "$DIR_TO_CHECK" -maxdepth 0 -type d -empty 2>/dev/null)" ]; then
echo "Empty directory"
else
echo "Not empty or NOT a directory"
fi
#!/bin/bash
if [ -d /path/to/dir ]; then
# the directory exists
[ "$(ls -A /path/to/dir)" ] && echo "Not Empty" || echo "Empty"
else
# You could check here if /path/to/dir is a file with [ -f /path/to/dir]
fi
With FIND(1) (under Linux and FreeBSD) you can look non-recursively at a directory entry via "-maxdepth 0" and test if it is empty with "-empty". Applied to the question this gives:
if test -n "$(find ./ -maxdepth 0 -empty)" ; then
echo "No new file"
exit 1
fi
What about testing if directory exists and not empty in one if statement
if [[ -d path/to/dir && -n "$(ls -A path/to/dir)" ]]; then
echo "directory exists"
else
echo "directory doesn't exist"
fi
Use the following:
count="$( find /path -mindepth 1 -maxdepth 1 | wc -l )"
if [ $count -eq 0 ] ; then
echo "No new file"
exit 1
fi
This way, you're independent of the output format of ls. -mindepth skips the directory itself, -maxdepth prevents recursively defending into subdirectories to speed things up.
A hacky, but bash-only, PID-free way:
is_empty() {
test -e "$1/"* 2>/dev/null
case $? in
1) return 0 ;;
*) return 1 ;;
esac
}
This takes advantage of the fact that test builtin exits with 2 if given more than one argument after -e: First, "$1"/* glob is expanded by bash. This results in one argument per file. So
If there are no files, the asterisk in
test -e "$1"*does not expand, so Shell falls back to trying file named*, which returns 1....except if there actually is one file named exactly
*, then the asterisk expands to well, asterisk, which ends up as the same call as above, ie.test -e "dir/*", just this time returns 0. (Thanks @TrueY for pointing this out.)If there is one file,
test -e "dir/file"is run, which returns 0.But if there are more files than 1,
test -e "dir/file1" "dir/file2"is run, which bash reports it as usage error, i.e. 2.
case wraps the whole logic around so that only the first case, with 1 exit status is reported as success.
Possible problems I haven't checked:
There are more files than number of allowed arguments--I guess this could behave similar to case with 2+ files.
Or there is actually file with an empty name--I'm not sure it's possible on any sane OS/FS.
This will do the job in the current working directory (.):
[ `ls -1A . | wc -l` -eq 0 ] && echo "Current dir is empty." || echo "Current dir has files (or hidden files) in it."
or the same command split on three lines just to be more readable:
[ `ls -1A . | wc -l` -eq 0 ] && \
echo "Current dir is empty." || \
echo "Current dir has files (or hidden files) in it."
Just replace ls -1A . | wc -l with ls -1A <target-directory> | wc -l if you need to run it on a different target folder.
Edit: I replaced -1a with -1A (see @Daniel comment)
Using an array:
files=( * .* )
if (( ${#files[@]} == 2 )); then
# contents of files array is (. ..)
echo dir is empty
fi
I think the best solution is:
files=$(shopt -s nullglob; shopt -s dotglob; echo /MYPATH/*)
[[ "$files" ]] || echo "dir empty"
thanks to
This is an anonymous edit of my answer that might or might not be helpful to somebody: A slight alteration gives the number of files:
files=$(shopt -s nullglob dotglob; s=(MYPATH/*); echo ${s[*]})
echo "MYPATH contains $files files"
This will work correctly even if filenames contains spaces.
if find "${DIR}" -prune ! -empty -exit 1; then
echo Empty
else
echo Not Empty
fi
EDIT: I think that this solution works fine with gnu find, after a quick look at the implementation. But this may not work with, for example, netbsd's find. Indeed, that one uses stat(2)'s st_size field. The manual describes it as:
st_size The size of the file in bytes. The meaning of the size
reported for a directory is file system dependent.
Some file systems (e.g. FFS) return the total size used
for the directory metadata, possibly including free
slots; others (notably ZFS) return the number of
entries in the directory. Some may also return other
things or always report zero.
A better solution, also simpler, is:
if find "${DIR}" -mindepth 1 -exit 1; then
echo Empty
else
echo Not Empty
fi
Also, the -prune in the 1st solution is useless.
EDIT: no -exit for gnu find.. the solution above is good for NetBSD's find. For GNU find, this should work:
if [ -z "`find \"${DIR}\" -mindepth 1 -exec echo notempty \; -quit`" ]; then
echo Empty
else
echo Not Empty
fi
This solution is using only shell built-ins:
function is_empty() {
typeset dir="${1:?Directory required as argument}"
set -- ${dir}/*
[ "${1}" == "${dir}/*" ];
}
is_empty /tmp/emmpty && echo "empty" || echo "not empty"
I could be mistaken, but I think this check should be sufficient:
[[ -s /path/to/dir ]] && echo "Dir not empty" || echo "Dir empty"
This is all great stuff - just made it into a script so I can check for empty directories below the current one. The below should be put into a file called 'findempty', placed in the path somewhere so bash can find it and then chmod 755 to run. Can easily be amended to your specific needs I guess.
#!/bin/bash
if [ "$#" == "0" ]; then
find . -maxdepth 1 -type d -exec findempty "{}" \;
exit
fi
COUNT=`ls -1A "$*" | wc -l`
if [ "$COUNT" == "0" ]; then
echo "$* : $COUNT"
fi
For any directory other than the current one, you can check if it's empty by trying to rmdir it, because rmdir is guaranteed to fail for non-empty directories. If rmdir succeeds, and you actually wanted the empty directory to survive the test, just mkdir it again.
Don't use this hack if there are other processes that might become discombobulated by a directory they know about briefly ceasing to exist.
If rmdir won't work for you, and you might be testing directories that could potentially contain large numbers of files, any solution relying on shell globbing could get slow and/or run into command line length limits. Probably better to use find in that case. Fastest find solution I can think of goes like
is_empty() {
test -z $(find "$1" -mindepth 1 -printf X -quit)
}
This works for the GNU and BSD versions of find but not for the Solaris one, which is missing every single one of those find operators. Love your work, Oracle.
This work for me, to check & process files in directory ../IN, considering script is in ../Script directory:
FileTotalCount=0
for file in ../IN/*; do
FileTotalCount=`expr $FileTotalCount + 1`
done
if test "$file" = "../IN/*"
then
echo "EXITING: NO files available for processing in ../IN directory. "
exit
else
echo "Starting Process: Found ""$FileTotalCount"" files in ../IN directory for processing."
# Rest of the Code
I made this approach:
CHECKEMPTYFOLDER=$(test -z "$(ls -A /path/to/dir)"; echo $?)
if [ $CHECKEMPTYFOLDER -eq 0 ]
then
echo "Empty"
elif [ $CHECKEMPTYFOLDER -eq 1 ]
then
echo "Not Empty"
else
echo "Error"
fi
The Question was:
if [ ./* == "./*" ]; then
echo "No new file"
exit 1
fi
Answer is:
if ls -1qA . | grep -q .
then ! exit 1
else : # Dir is empty
fi
[ $(ls -A "$path" 2> /dev/null | wc -l) -eq 0 ] && echo "Is empty or not exists." || echo "Not is empty."
I might have missed an equivalent to this, which works on Unix
cd directory-concerned
ls * > /dev/null 2> /dev/null
return-code (test value of $?) will be 2 if nothing or 0 something found.
Note this ignores any '.' files and will probably return 2 if any of these exist without any other 'normal' filenames.
More solutions with find
# Tests that a directory is empty.
# Will print error message if not empty to stderr and set return
# val to non-zero (i.e. evaluates as false)
#
function is_empty() {
find $1 -mindepth 1 -exec false {} + -fprintf /dev/stderr "%H is not empty\n" -quit
# prints error when dir is not empty to stderr
# -fprintf /dev/stderr "%H is not empty\n"
#
# -exec false {} +
# sets the return value (i.e. $?) to indicate error
#
# --quit
# terminate after the first match
}
examples
#!/bin/bash
set -eE # stop execution upon error
function is_empty() {
find $1 -mindepth 1 -exec false {} + -fprintf /dev/stderr "%H is not empty\n" -quit
}
trap 'echo FAILED' ERR
#trap "echo DONE" EXIT
# create a sandbox to play in
d=$(mktemp -d)
f=$d/blah # this will be a potention file
set -v # turn on debugging
# dir should be empty
is_empty $d
# create a file in the dir
touch $f
! is_empty $d
# this will cause the script to fail because the dir is not empty
is_empty $d
# this line will not execute
echo "we should not get here"