[ -f /*.txt ]
would return true only if there's one (and only one) non-hidden file in / whose name ends in .txt and if that file is a regular file or a symlink to a regular file.
That's because wildcards are expanded by the shell prior to being passed to the command (here [).
So if there's a /a.txt and /b.txt, [ will be passed 5 arguments: [, -f, /a.txt, /b.txt and ]. [ would then complain that -f is given too many arguments.
If you want to check that the *.txt pattern expands to at least one non-hidden file (regular or not), in the bash shell:
shopt -s nullglob
set -- *.txt
if [ "$#" -gt 0 ]; then
./script "$@" # call script with that list of files.
fi
# Or with bash arrays so you can keep the arguments:
files=( *.txt )
# apply C-style boolean on member count
(( ${#files[@]} )) && ./script "${files[@]}"
shopt -s nullglob is bash specific (shopt is, nullglob actually comes from zsh), but shells like ksh93, zsh, yash, tcsh have equivalent statements.
With zsh, the test for are there files matching a pattern can be written using an anonymous function and the N (for nullglob) and Y1 (to stop after the first find) glob qualifier:
if ()(($#)) *.txt(NY1); then
do-something
fi
Note that those find those files by reading the contents of the directory, it doesn't try and access those files at all which makes it more efficient than solutions that call commands like ls or stat on that list of files computed by the shell.
The standard sh equivalent would be:
set -- [*].txt *.txt
case "$1$2" in
('[*].txt*.txt') ;;
(*) shift; script "$@"
esac
The problem is that with Bourne or POSIX shells, if a pattern doesn't match, it expands to itself. So if *.txt expands to *.txt, you don't know whether it's because there's no .txt file in the directory or because there's one file called *.txt. Using [*].txt *.txt allows to discriminate between the two.
Now, if you want to check that the *.txt matches at least one regular file or symlink to regular file (like your [ -f *.txt ] suggests you want to do), or that all the files that match *.txt are regular files (after symlink resolution), that's yet another matter.
With zsh:
if ()(($#)) *.txt(NY1-.); then
echo "there is at least one regular .txt file"
fi
if ()(($#)) *.txt(NY1^-.); then
echo "there is at least one non-regular .txt files"
fi
(remove the - if you want to do the test prior to symlink resolution, that is consider symlinks as non-regular files whether they point to regular files or not).
/? Also, you're missing a semicolon beforefi. – depquid Jun 13 '13 at 15:44findas explained here on stackoverflow. – Joshua Goldberg Nov 18 '19 at 17:48