Bash arguments

From wikinotes
Revision as of 00:44, 10 November 2021 by Will (talk | contribs) (→‎Argument Variables)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Arguments are handled the same way for functions and modules.


Argument Variables

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

$?         # last command exit code
$$         # pid
$#         # number of arguments
$@         # array of all arguments
${@[$#]}   # last argument
${@:2}     # skip 1st argument, but all arguments afterwards

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