Bash globbing and argument passing

argumentsbashglobwildcards

I have the following simplified bash script

#!/bin/bash

files=("$@")

if [ "X$files" = "X" ]; then
  files=$HOME/print/*.pdf;
fi

for file in "${files[@]}"; do
  ls "$file";
done

If I pass arguments (file names) as parameters this script will print the proper file names. On the other hand, if I don't pass arguments, it will print

/home/user/print/*.pdf: No such file or directory

Why are the file names not expanded in this case, and how do I fix it? Note that I use the files=("$@") and "${files[@]}" constructs because I read that it is to be preferred over the usual "files=$*".

Best Answer

You're assigning files as a scalar variable instead of an array variable.

In

 files=$HOME/print/*.pdf

You're assigning some string like /home/highsciguy/print/*.pdf to the $files scalar (aka string) variable.

Use:

files=(~/print/*.pdf)

or

files=("$HOME"/print/*.pdf)

instead. The shell will expand that globbing pattern into a list of file paths, and assign each of them to elements of the $files array.

The expansion of the glob is done at the time of the assignment.

You don't have to use non-standard sh features, and you could use your system's sh instead of bash here by writing it:

#!/bin/sh -

[ "$#" -gt 0 ] || set -- ~/print/*.pdf

for file do
  ls -d -- "$file"
done

set is to assign the "$@" array of positional parameters.

Another approach could have been to store the globbing pattern in a scalar variable:

files=$HOME/print/*.pdf

And have the shell expand the glob at the time the $files variable is expanded.

IFS= # disable word splitting
for file in $files; do ...

Here, because $files is not quoted (which you shouldn't usually do), its expansion is subject to word splitting (which we've disabled here) and globbing/filename generation.

So the *.pdf will be expanded to the list of matching files. However, if $HOME contained wildcard characters, they could be expanded too, which is why it's still preferable to use an array variable.

Related Question