Bash arguments: Difference between revisions

From wikinotes
Line 80: Line 80:
Say for example you wanted to accept the following calls (similar to ls).
Say for example you wanted to accept the following calls (similar to ls).
<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
foo -abc       # same as `foo -a -b -c`
foo -abc           # same as `foo -a -b -c`
foo -a -bc     # same as `foo -a -b -c`
foo -a -bc         # same as `foo -a -b -c`
foo -a --other # same as `foo -a -b -c --other`
foo -a --other     # same as `foo -a -b -c --other`
foo -abc -depth 2  # same as `foo -a -b -c -depth 2`
</syntaxhighlight>
</syntaxhighlight>


<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
# these are all available single-letter params
# ex: foo -a -b -c
avail_letters="abc"
# accept as many as avail_letters,
# only in combinations of avail_letters
case_value=$(
    for ((i=1; i<=${#avail_letters}; i++)); do
        echo -n "|-$(printf "[${avail_letters}]%.0s" {1..$i})"
    done
)
# strip 1st '|'
case_value="${case_value:1}"  # "-[abc]|-[abc][abc]|-[abc][abc][abc]"
# now use your param case statement
# now use your param case statement
case $1 in
case $1 in
     $case_value)
     -h|--help)
        for ((i=2; i<=${#1}; i++)); do  # each letter, after '-'
            case ${1[$i]} in
                a)
                    echo "a received"
                    ;;
                b)
                    echo "b received"
                    ;;
                c)
                    echo "c received"
                    ;;
            esac
        done
        shift
        ;;
    --help)
         echo "help me obi-wan kenobi"
         echo "help me obi-wan kenobi"
        return 0
         ;;
         ;;
  --other)
    --other)
         echo "other"
         echo "other"
         ;;
         ;;
     esac
     -*)
        param="$1"
        if echo "$param" | grep -E '^-[abc]+$' 2>&1 > /dev/null ; then
            for ((i=2; i<=${#param}; i++)); do  # each letter, after '-'
                case ${param[$i]} in
                    a)
                        echo "a received"
                        ;;
                    b)
                        echo "b received"
                        ;;
                    c)
                        echo "c received"
                        ;;
                esac
            done
            shift
        elif [[ "$1" == "-depth" ]] ; then
            local DEPTH=$1
            shift 2
        fi
        ;;
esac
esac
</syntaxhighlight>
</syntaxhighlight>

Revision as of 19:23, 18 July 2021

Arguments are handled the same way for functions and modules.


Argument Variables

$1   # first argument
$2   # second argument
# ... etc.

$#         # number of arguments
$@         # array of all arguments
${@[$#]}   # last argument


Parsing Arguments

Regular Params

parsing arguments in this way, it does not matter the order that parameters are passed in, or if they have are keyword arguments with a value.

# PARSE ALL ARGUMENTS

while [ $# -gt 0 ] ; do
    case $1 in
        -f|--file)
            filepath=$2
            shift 2        # jump forwards twice (once for '--file', once for 'filepath')
            ;;
        -d|--debug)
            debug=1
            shift
            ;;
        *)
            echo "default behaviour"
            ;;
    esac
done

Here is another variation

function parse_args() {
    args=($@)
    for ((i=0; i <= ${#args[@]}; i++))
    do
        case "${args[$i]}" in
            -h|--help)
                print_help
                exit 0
                ;;
            -L)
                LOCAL_PORTS+=( ${args[$i+1]} )
                ((i++))
                ;;
            -R)
                REMOTE_PORTS+=( ${args[$i+1]} )
                ((i++))
                ;;
            -t|--test)
                TEST=1
                ;;
            *)
                SSH_PARAMS+=" ${args[$i]}"
                ;;
        esac
    done
}

Combined Single Letter Params

Bash doesn't support regex, so we're limited to manually repeating character ranges.

Say for example you wanted to accept the following calls (similar to ls).

foo -abc           # same as `foo -a -b -c`
foo -a -bc         # same as `foo -a -b -c`
foo -a --other     # same as `foo -a -b -c --other`
foo -abc -depth 2  # same as `foo -a -b -c -depth 2`
# now use your param case statement
case $1 in
    -h|--help)
        echo "help me obi-wan kenobi"
        return 0
        ;;
    --other)
        echo "other"
        ;;
    -*)
        param="$1"
        if echo "$param" | grep -E '^-[abc]+$' 2>&1 > /dev/null ; then
            for ((i=2; i<=${#param}; i++)); do  # each letter, after '-'
                case ${param[$i]} in
                    a)
                        echo "a received"
                        ;;
                    b)
                        echo "b received"
                        ;;
                    c)
                        echo "c received"
                        ;;
                esac
            done
            shift
        elif [[ "$1" == "-depth" ]] ; then
            local DEPTH=$1
            shift 2
        fi
        ;;
esac

Counting Arguments

if [ $# -gt 2 ]; then
    echo "if there are more than 2 arguments"
fi
# see also
-eq   # equal
-ne   # not equal

-gt   # greater than
-ge   # greater or equal
-lt   # less than
-le   # less or equal

Iterating Arguments

for arg in "${args[@]}"; do
   echo $arg
done


for (( i=1; i<=(($#-1)); i++ )) ; do
	echo ${@[$i]};
done