If I want to check for the existence of a single file, I can test for it using test -e filename
or [ -e filename ]
.
Supposing I have a glob
set -- glob*
if [ -f "$1" ]; then
echo "It matched"
fi
When there isn't a match for glob*
, then $1
will contain 'glob*'
. The test -f "$1"
won't be true because the glob*
file doesn't exist.
This works with sh and derivates: ksh and bash. It doesn't create any sub-shell. $(..)
and `...`
commands create a sub-shell; they fork a process, and therefore are slower than this solution.
Like this in bash (test files containing pattern
):
shopt -s nullglob
compgen -W *pattern* &>/dev/null
case $? in
0) echo "only one file match" ;;
1) echo "more than one file match" ;;
2) echo "no file match" ;;
esac
It's far better than compgen -G
: because we can discriminates more cases and more precisely.
Can work with only one wildcard *
I have yet another solution:
if [ "$(echo glob*)" != 'glob*' ]
This works nicely for me. Are there some corner cases I miss?
ls | grep -q "glob.*"
Not the most efficient solution (if there's a ton of files in the directory it might be slowish), but it's simple, easy to read and also has the advantage that regexes are more powerful than plain bash glob patterns.
test -e has the unfortunate caveat that it considers broken symbolic links to not exist. So you may want to check for those, too.
function globexists {
test -e "$1" -o -L "$1"
}
if globexists glob*; then
echo found
else
echo not found
fi
#!/usr/bin/env bash
# If it is set, then an unmatched glob is swept away entirely --
# replaced with a set of zero words --
# instead of remaining in place as a single word.
shopt -s nullglob
M=(*px)
if [ "${#M[*]}" -ge 1 ]; then
echo "${#M[*]} matches."
else
echo "No such files."
fi