Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RegEx in bash-script (for-loop)

Tags:

linux

bash

shell

sh

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.

like image 787
default-user Avatar asked Feb 27 '23 05:02

default-user


2 Answers

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.

like image 145
John Kugelman Avatar answered Mar 11 '23 21:03

John Kugelman


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.

like image 32
Dennis Williamson Avatar answered Mar 11 '23 19:03

Dennis Williamson