Calvin's Blog

Bash: Script options parsing with getopts

∙ scripting∙ bash
article meme

How to use getopts

The man page for getopts can be found here

When writing bash scripts it can be useful to accept arguments to alter the behavior of your script. Parsing arguments by hand is not hard, but not fun to repeat in various scripts. I learned today that there is a built in function for this called getopts!

The syntax for using getopts is getopts optstring name

getopts can be used with a while loop in a bash script to parse all options in a loop, We will see an example of that below.

optstring argument

Where optstring is a string that tells getopts what your arguments are called. Colons : are also used to denote that an argument also takes a value. If the optstring starts with a : then errors and other logs are suppressed from getopts. Here are some examples

The optstring parses arguments that follow the POSIX.1‐2017 12.2 Utility Syntax Guidelines 3 through 10

These guidelines are worth a ready, but a notable part of the guidelines is that options must be prepended with a - and be only one character. For example -a for a flag and -c value for options that take a value.

name argument

The name argument is the name of the shell variable that will be set to the option character that was found.

Shell Variables of Note

Example Script

#! /bin/bash

aflag=
bflag=
cflag=
dflag=

echo_getopts_vars() {
    # This prints out the relevant variables used by getopts 
    # so we can see them at any given point in time.
    echo "name = $name"
    echo "OPTARG = $OPTARG"
    echo "LANG = $LANG"
    # echo "LC_ALL = $LC_ALL"
    # echo "LC_CTYPE = $LC_CTYPE"
    # echo "LC_MESSAGES = $LC_MESSAGES"
    # echo "NLSPATH = $NLSPATH"
    echo "OPTIND = $OPTIND"
}

printf "pre getopts call values:\n"
echo "-----"
echo_getopts_vars
echo "-----"
# printf "\n"

loopcount=0

# : as the first char in the optstring suppresses errors from getopts
while getopts :ab:cd: name
do
    printf "\npost getopts call %d\n" "$loopcount"
    echo "-----"
    echo_getopts_vars
    case $name in
    a)    aflag=1;;
    b)    bflag=1
            bval="$OPTARG";;
    c)    cflag=1;;
    d)    dflag=1
            dval="$OPTARG";;
    ?)   printf "Usage: %s: [-a] [-b value] [-c] [-d value] args\n" $0
            exit 2;;
    esac
    loopcount=$[$loopcount+1]
    echo "-----"
done
printf "\n"
# If the -a options is present
if [ ! -z "$aflag" ]; then
    printf "Option -a specified\n"
fi
# if the -b options is present with a value provided
if [ ! -z "$bflag" ]; then
    printf 'Option -b "%s" specified\n' "$bval"
fi
# If the -c options is present
if [ ! -z "$cflag" ]; then
    printf "Option -c specified\n"
fi
# if the -d options is present with a value provided
if [ ! -z "$dflag" ]; then
    printf 'Option -d "%s" specified\n' "$dval"
fi

# This shift is using the OPTIND variable managed by getopts to shift the 
# arguments over such that only the items not processed by getopts 
# will remain in $*
shift $(($OPTIND - 1))
printf "Remaining arguments are:\n-----\n%s\n-----\n" "$*"