Parsing Command-Line Parameters

Basic

The parameters are in the variables $1, $2, etc. The special variable $# contains the number of parameters. Further, $0 contains the name of the script how it was called by the user.

If there are more than 9 parameters or to process the parameters one by one, the build-in command shift moves all parameters to the next lower variable.

param1.sh

#!/bin/bash
echo $1 $2 $3
shift
echo $1 $2 $3

executed with parameters "a", "b", and "c":

$ ./param1.sh a b c
a b c
b c

This can be used for simple processing of multiple input options:

param2.sh

echo $@
while [[ $# -gt 0 ]]; do
    echo $1
    shift
done

The first line prints all parameters (another special variable), then the while loop prints $1 and shifts the remaining parameters until the number of parameters $# is 0.

$ ./param2.sh a b c
a b c
a
b
c

This can be extended with if or case to check for actual parameters (examples for that are in the following examples).

The major advantage of the tools presented in the following are their normalizing capabilities. If multiple switches (parameters without argument) are given together as -abc, the normalizing rewrites them to -a -b -c.

Getopt

getopt is a binary that parses the parameters and creates a unified (normalized) string that can be parsed. The line eval set -- "$ARGS" sets the parameters of the script to the normalized version processed by getopt.

param3.sh

ARGS=$(getopt -o 'n:v::h' -l 'help' -- "$@")   # parse parameters and store normalized string in $ARGS
eval set -- "$ARGS";                           # set parameters to preprocessed string $ARGS

while [[ $# -gt 0 ]]; do
    echo -n "[$1] "
    case "$1" in
        -n)
            echo "found parameter -n"
            echo "     required parameter is '$2'"
            shift # remove required parameter
            ;;
        -v)
            echo "that's a -v"
            if [[ -n $2 ]]; then
                echo "     optional parameter '$2'"
            else
                echo "     no optional parameter provided"
            fi
            shift # remove optional parameter 
                  # (was inserted as /empty/ if not provided by user
            ;;
        -h|--help)
            echo "someone asked for help with -h or --help"
            ;;
        --)
            echo "that was the last option, following are free parameters"
            ;;
        *)
            echo "thats an unknown parameter"
    esac
    shift
done

The optstring (after -o) defines the valid parameters. Like in the C library function getopt(), the parameters can have an optional argument (two colons) or a required one (one colon). In the example above, the -n must be given an argument, the -v has an optional argument. The -h and --help never expect an argument.

$ ./param3.sh -n3 -v -v3 -h --help
[-n] found parameter -n
     required parameter is '3'
[-v] that's a -v
     no optional parameter provided
[-v] that's a -v
     optional parameter '3'
[-h] someone asked for help with -h or --help
[--help] someone asked for help with -h or --help
[--] that was the last option, following are free parameters

See the man-page to getopt for more details.

Getopts

This is a build-in of Bash. And as such, it is somehow easier and more straightforward to use as it can directly be used in the while loop:

param4.sh

while getopts n:v::h PARAM; do
    echo -n "[$PARAM] "
    case "$PARAM" in
        n)
            echo "found parameter -n"
            echo "     required parameter is '$OPTARG'"
            ;;
        v)
            echo "that's a -v"
            if [[ -n $OPTARG ]]; then
                echo "     optional parameter '$OPTARG'"
            else
                echo "     no optional parameter provided"
            fi
            ;;
        h)
            echo "someone asked for help with -h"
            ;;
    esac
done

# additional free arguments:
shift $(( OPTIND - 1))
echo "more parameters: '$@'"

The changes are: * getopts is directly put in the while loop and puts its result in $PARAM. * It does not support long options (e.g. --help) * The cases are only the letter while getopt included the dash. * Additional non-option (free) arguments remain unread and can be processed later (after shifting all processed parameters).

social