I want to check whether an input string refers to a file name - not a wildcard string like *.txt.

This doesn't work:

if [ -f "$1" ];

Because $1 gets expanded to *.txt, which gets expanded to, say foo.txt bar.txt, which gets passed to test -f.

Short of explicitly checking for wildcard characters, is there a general way to perform a shell substitution, and then prevent any globbing?


No, globs are not expanded when quoted, so:

set -- '*.txt'
[ -f "$1" ]

Will check whether the file called *.txt in the current directory is a regular file or a symlink to a regular file.

[ -f $1 ]

would be a problem ($1 would undergo word splitting (here not doing anything with the default value of $IFS) and filename generation).

If you wanted to check whether there were regular files with a .txt extension, you'd need a loop or use find or zsh glob qualifiers.

set -- *.txt
for f do
  if [ -f "$f" ]; then
    echo "there is at least one regular file with a .txt extension here"

Or if the pattern is found in $1:

IFS= # disable the globbing part of the split+glob operator
set -- $1
for f do... # as above


echo "$#files regular files with a .txt extension here"


find -L . ! -name . -prune ! -name '.*' -name '*.txt' -type f | grep -q . &&
  echo there are regular .txt files in here
  • Thanks, I do need to use the $1 though. Perhaps I should have explained the task: a script that does when thing when passed a single filename (displays it), and another thing when passed a directory or file mask (runs ls). The "*.txt" is just one example of something that might be passed to the script. – Steve Bennett Aug 7 '14 at 12:03
  • 2
    @SteveBennett, if your script is called as my-script *.txt, then the calling shell will expand that *.txt before calling the script. my-script will receive bar.txt in $1 and foo.txt in $2... You shouldn't need to expand wildcards in your script. – Stéphane Chazelas Aug 7 '14 at 12:08
  • Oh...yes, you're right. Ok, so if my script receives two arguments, it was given a wildcard. No way to distinguish between my-script foo.txt and my-script *.txt if there is only one txt file? – Steve Bennett Aug 7 '14 at 12:18
  • 2
    No way no. Just as there's no way to tell if the script was called as my-script $files or my-script "${files[@]}" or my-script $(ls). – Stéphane Chazelas Aug 7 '14 at 12:27
  • 1
    @SteveBennett, check for $# (the number of arguments) – Stéphane Chazelas Aug 7 '14 at 14:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.