I want to parse the arguments given to a shell script by using a for-loop. Now, assuming I have 3 arguments, something like
for i in $1 $2 $3
should do the job, but I cannot predict the number of arguments, so I wanted use an RegEx for the range and $# as the number of the last argument. I don't know how to use these RegEx' in a for-loop, I tried something like
for i in $[1-$#]
which doesn't work. The loop only runs 1 time and 1-$# is being calculated, not used as a RegEx.
A for
loop by default will loop over the command-line arguments if you don't specify the in
clause:
for arg; do
echo "$arg"
done
If you want to be explicit you can get all of the arguments as "$@"
. The above loop is equivalent to:
for arg in "$@"; do
echo "$arg"
done
From the bash man page:
Special Parameters
$@
— Expands to the positional parameters, starting from one. When the expansion occurs within double quotes, each parameter expands to a separate word. That is,"$@"
is equivalent to"$1" "$2" ...
. If the double-quoted expansion occurs within a word, the expansion of the first parameter is joined with the beginning part of the original word, and the expansion of the last parameter is joined with the last part of the original word. When there are no positional parameters,"$@"
and$@
expand to nothing (i.e., they are removed).
For heavy-duty argument processing, getopt
+ shift
is the way to go. getopt
will pre-process the command-line to give the user some flexibility in how arguments are specified. For example, it will expand -xzf
into -x -z -f
. It adds a --
argument after all the flags which separates flags from file names; this lets you do run cat -- -my-file
to display the contents of -my-file
without barfing on the leading dash.
Try this boilerplate code on for size:
#!/bin/bash
eval set -- "$(getopt -o a:bch -l alpha:,bravo,charlie,help -n "$0" -- "$@")"
while [[ $1 != -- ]]; do
case "$1" in
-a|--alpha)
echo "--alpha $2"
shift 2
;;
-b|--bravo)
echo "--bravo"
shift
;;
-c|--charlie)
echo "--charlie"
shift
;;
-h|--help)
echo "Usage: $0 [-a ARG] [-b] [-c]" >&2
exit 1
;;
esac
done
shift
Notice that each option has a short a long equivalent, e.g. -a
and --alpha
. The -a
flag takes an argument so it's specified as a:
and alpha:
in the getopt
call, and has a shift 2
at the end of its case.
Another way to iterate over the arguments which is closer to what you were working toward would be something like:
for ((i=1; i<=$#; i++))
do
echo "${@:i:1}"
done
but the for arg
syntax that John Kugelman showed is by far preferable. There are, however, times when array slicing is useful. Also, in this version, as in John's, the argument array is left intact. Using shift
discards its elements.
You should note that what you were trying to do with square brackets is not a regular expression at all.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With