RegEx in bash-script (for-loop)
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 predic开发者_如何学Ct 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.
Basic
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).
Advanced
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.
I suggest doing something else instead:
while [ -n "$1" ] ; do
# Do something with $1
shift
# Now whatever was in $2 is now in $1
done
The shift
keyword moves the content of $2 into $1, $3 into $2, etc. pp.
Let's say the arguments where:
a b c d
After a shift
, the arguments are now:
b c d
With the while loop, you can thus parse an arbitrary number of arguments and can even do things like:
while [ -n "$1" ] ; do
if [ "$1" = "-f" ] ; then
shift
if [ -n "$1" ] ; then
myfile="$1"
else
echo "-f needs an additional argument"
end
fi
shift
done
Imagine the arguments as being an array and $n being indexes into that array. shift
removes the first element, so the index 1 now references the element that was at index 2 prior to shift
. I hope you understand what I want to say.
精彩评论