Why are quotes necessary for files argument when calling this Bash script?

When you call a program

testscript *.txt

then your shell does the expansion and works out all the values. So it might, effectively call your program as

testscript file1.txt file2.txt file3.txt file4.txt

Now your program only looks at $1 and so only works on file1.txt.

By quoting on the command line you are passing the literal string *.txt to the script, and that is what is stored in $1. Your for loop then expands it.

Normally you would use "$@" and not $1 in scripts like this.

This is a "gotcha" for people coming from CMD scripting, where the command shell doesn't do globbing (as it's known) and always passes the literal string.


Without quotes the shell expands *.txt before invoking the script, so $1 is only the first file that gets expanded. All of the txt files are arguments to your script at that point (assuming there aren't too many).

With quotes that string is passed without being expanded into the script, which then lets the for do the expansion, as you're hoping for.