Bash For Arg

on

shell scripting, tested in Bash 5.0.16(1)-release (x86_64-pc-linux-gnu), on grml 2020.06 (VirtualBox VM)

Argument Loop, my definition

This article demonstrates looping for/while-statements over passed-in arguments via whitespace-delimited (quote-escaped) words that follow the invocation command.

I do not consider the invoking command to be an argument. If you want the invoking command use "$0" or to get the whole command line as a string use "$@".

"For Arg" is a Quick and Repeatable Looping Method

I haven't seen any documentation about this, so keep that in mind. I discovered it in a shell script found in /bin/bzdiff of my grml live instance. This is so easy to use and memorable, it almost seems too good to be true. Unless I'm missing something destructive about this, it appears to be somewhat of a hidden scripting gem. I've seen other tutorials where you reconstruct the args by indexing off "$@", that seems like overkill now that I learned how to do it this way.

print-args.bash

#!/bin/bash

for ARG;
do
    echo "$ARG"
done

command line

chmod +x print-args.bash
./print-args.bash 1 "2" 'three' "4th arg" '5th arg'

output

1
2
three
4th arg
5th arg

Simple enough? I've explained this in greater detail in the Additional Notes section below.

While Shift Method (not repeatable)

Here is a completely different way to enumerate the arguments, using a while loop and shift. I discovered this method in grml code, in a check4progs function (checks for program names existing in each directory specified in PATH).

This is a very efficient way to process arguments, and I assume the arguments are cleared out of memory on each argument shift. Use this when you know you only need to iterate in one pass for efficiency. Shift will move all arguments left 1 spot and the left-most argument "$1" will be replaced by "$2", so really you only need to access "$1".

say-goodbye.bash

#!/bin/bash

while [ $# -gt 0 ]
do
    echo "Goodbye ${1}"
    shift
done

command line

chmod +x say-goodbye.bash
./say-goodbye.bash "Taco Bell Enchirito" "Wendy's Chili, Chips & Cheese"

output

Goodbye Taco Bell Enchirito
Goodbye Wendy's Chili, Chips & Cheese
[archived food pics]

Additional Notes

for ARG; do echo "$ARG"; done

If you are trying to make sense of what is happening here, that is where things get tricky. Nowhere are you specifying that you are actually enumerating arguments, the word ARG could have been named anything (as demonstrated below). It appears that a for statement that doesn't specify what is being iterated will have assumed it was arguments that was wanted. After iterating the arguments they can be re-iterated again (also shown below).

print-args-twice.bash

#!/bin/bash

for ARG;
do
    echo "$ARG"
done

for blah;
do
    echo "$blah"
done 

command line

chmod +x print-args-twice.bash
./print-args-twice.bash a b

output

a
b
a
b

Alternative test command syntax

The while condition can also be written with the test command syntax which is equivalent to the square bracket notation.


#while [ $# -gt 0 ]

while test $# -gt 0
do
    echo "Goodbye ${1}"
    shift
done