Easy getopt for a BASH script

getopt is extremely useful for quickly being able to add options and arguments to your program without having to worry much about the parsing yourself. There are getopt libraries for many languages but what about BASH? It turns out there are actually two versions of getopt that you can use in your BASH scripts; a command line utility getopt provided by the util-linux package, and a bash builtin getopts. I have provided a brief overview of each in the following sections.

getopt: The command line utility


An example of a bash script using getopt to allow the user to specify one of three colors (blue, red, or green) is shown below. The user can specify -b to imply the color is blue or can specify --color=blue to do the same. If the user uses the long option --color they must specify an argument to denote what color.

#!/bin/bash

# Call getopt to validate the provided input. 
options=$(getopt -o brg --long color: -- "$@")
[ $? -eq 0 ] || { 
    echo "Incorrect options provided"
    exit 1
}
eval set -- "$options"
while true; do
    case "$1" in
    -b)
        COLOR=BLUE
        ;;
    -r)
        COLOR=RED
        ;;
    -g)
        COLOR=GREEN
        ;;
    --color)
        shift; # The arg is next in position args
        COLOR=$1
        [[ ! $COLOR =~ BLUE|RED|GREEN ]] && {
            echo "Incorrect options provided"
            exit 1
        }
        ;;
    --)
        shift
        break
        ;;
    esac
    shift
done

echo "Color is $COLOR"
exit 0;


And here are the outputs from some test runs:

dusty@media: content>./test -b
Color is BLUE
dusty@media: content>./test -r
Color is RED
dusty@media: content>./test -g
Color is GREEN
dusty@media: content>./test -z
getopt: invalid option -- 'z'
Incorrect options provided
dusty@media: content>./test --color=BLUE
Color is BLUE
dusty@media: content>./test --color
getopt: option '--color' requires an argument
Incorrect options provided
dusty@media: content>./test --color=YELLOW
Incorrect options provided

getopts: The bash builtin


We can almost exactly perform the same task with the getopts builtin. Unfortunately the getopts builtin does not support long options so I created a new -c short option and added a : to the line to specify that it takes an argument (just like --color from the first example). The code is shown below. Notice that getopts actually uses the $OPTARG variable for options that have arguments which makes for easy to read code.

#!/bin/bash

while getopts "brgc:" OPTION; do
    case $OPTION in
    b)
        COLOR=BLUE
        ;;
    r)
        COLOR=RED
        ;;
    g)
        COLOR=GREEN
        ;;
    c)
        COLOR=$OPTARG
        [[ ! $COLOR =~ BLUE|RED|GREEN ]] && {
            echo "Incorrect options provided"
            exit 1
        }
        ;;
    *)
        echo "Incorrect options provided"
        exit 1
        ;;
    esac
done

echo "Color is $COLOR"
exit 0;


And finally a similar set of output from test runs:

dusty@media: content>./test2 -b
Color is BLUE
dusty@media: content>./test2 -r
Color is RED
dusty@media: content>./test2 -g
Color is GREEN
dusty@media: content>./test2 -z
./test2: illegal option -- z
Incorrect options provided
dusty@media: content>./test2 -c BLUE
Color is BLUE
dusty@media: content>./test2 -c
./test2: option requires an argument -- c
Incorrect options provided
dusty@media: content>./test2 -c YELLOW
Incorrect options provided
dusty@media: content>


Cheers!

Dusty Mabe