I have a basic bash script that currently looks for input of a specified file as a variable and if it is blank, processes the whole directory.

if i specify a file on execution such as script.sh file1.txt then it processes that file.

What I want and cannot figure out, is how to specify multiple files with wildcards. For example:

script.sh file*.txt

I guess it needs some simple loop, but I could not find any examples that matched this scenario.

When I try to do a loop, it only processes the first match.

if [ $# -eq 0 ]; then
    echo "no argument supplied, pulling all file from tick_tock"

    for i in /var/tank/tick_tock/*.txt; do
        cp "$i" /var/tank/awaiting/
echo "you supplied $1"
cp "$1" /var/tank/awaiting/

2 Answers 2


If you invoke a script with:

$ script.sh file*.txt

and if there are matches, then the shell will expand that glob to the list of files matches. Assume, for instance, that you have file1.txt, file2.txt, and file3.txt, then the above command is equivalent to:

$ script.sh file1.txt file2.txt file3.txt

The order may differ, but that's not important here.

One option do handling the files in that case is a loop like:

while [[ $# -ne 0 ]]; do
    # process ${1}

The shift will discard the old ${1} and shift the remaining parameters "left" by one (2 becomes 1, 3 becomes 2, etc). The shift also updates $#.

For example:


while [[ $# -ne 0 ]]; do
    echo ${1}

If I run that script, I see:

$ ./script.sh a b c
  • 1
    Globs are supposed to be expanded in the locale sort order, so file[123].txt should come in that order. Not that you'd usually need to care or rely on that, but it can be useful with e.g. file names containing timestamps.
    – ilkkachu
    Commented Jul 28, 2020 at 7:40

The thing here is that the wildcard pattern expands to multiple arguments, not just to a single argument at $1. The others are in $2, $3, etc. You can't index into those with standard shell features, but usually you don't need to: you can access the list of arguments to the script with "$@". So:

if [ "$#" -eq 0 ]; then
    echo "no arguments"
    echo "$# arguments:"
    for x in "$@"; do
        echo " $x"     # or do whatever with $x

Something like cp -- "$@" /var/tank/awaiting/ would in turn call cp with the files the script got as arguments. The -- there prevents any following arguments from being taken as options to cp.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .