开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜