I have a complex command that I\'d like to make a shell/bash script of. I can write it in terms of $1
easily:
foo $1 args -o $1.ext
Use "$@"
to represent all the arguments:
for var in "$@"
do
echo "$var"
done
This will iterate over each argument and print it out on a separate line. $@ behaves like $* except that when quoted the arguments are broken up properly if there are spaces in them:
sh test.sh 1 2 '3 4'
1
2
3 4
Amplifying on baz's answer, if you need to enumerate the argument list with an index (such as to search for a specific word), you can do this without copying the list or mutating it.
Say you want to split an argument list at a double-dash ("--") and pass the arguments before the dashes to one command, and the arguments after the dashes to another:
toolwrapper() {
for i in $(seq 1 $#); do
[[ "${!i}" == "--" ]] && break
done || return $? # returns error status if we don't "break"
echo "dashes at $i"
echo "Before dashes: ${@:1:i-1}"
echo "After dashes: ${@:i+1:$#}"
}
Results should look like this:
$ toolwrapper args for first tool -- and these are for the second
dashes at 5
Before dashes: args for first tool
After dashes: and these are for the second
getopt Use command in your scripts to format any command line options or parameters.
#!/bin/bash
# Extract command line options & values with getopt
#
set -- $(getopt -q ab:cd "$@")
#
echo
while [ -n "$1" ]
do
case "$1" in
-a) echo "Found the -a option" ;;
-b) param="$2"
echo "Found the -b option, with parameter value $param"
shift ;;
-c) echo "Found the -c option" ;;
--) shift
break ;;
*) echo "$1 is not an option";;
esac
shift
You can also access them as an array elements, for example if you don't want to iterate through all of them
argc=$#
argv=("$@")
for (( j=0; j<argc; j++ )); do
echo "${argv[j]}"
done
For simple cases you can also use shift
.
It treats the argument list like a queue. Each shift
throws the first argument out and the
index of each of the remaining arguments is decremented.
#this prints all arguments
while test $# -gt 0
do
echo "$1"
shift
done
Note that Robert's answer is correct, and it works in sh
as well. You can (portably) simplify it even further:
for i in "$@"
is equivalent to:
for i
I.e., you don't need anything!
Testing ($
is command prompt):
$ set a b "spaces here" d
$ for i; do echo "$i"; done
a
b
spaces here
d
$ for i in "$@"; do echo "$i"; done
a
b
spaces here
d
I first read about this in Unix Programming Environment by Kernighan and Pike.
In bash
, help for
documents this:
for NAME [in WORDS ... ;] do COMMANDS; done
If
'in WORDS ...;'
is not present, then'in "$@"'
is assumed.