Search code examples
bashshellgetopts

Bash - optional argument required but not passed for use in getopts


How do I flag an error in a bash script which requires an argument for getopt, but the user didn't pass it? e.g. the script below requires an argument for option "t":

#!/bin/bash
while getopts "ht:" OPTION
do
    case $OPTION in
        h)
            echo "Hi"
            ;;
        t)
            echo You entered $OPTARG
            ;;
    esac
done

I want to catch the below error and print something else and exit. Currently, it goes on to evaluate more arguments without exiting.

$ ./x.sh -h -t aa     # (this is fine)
Hi
You entered aa

$ ./x.sh -h -t       # (this is not handled)
Hi
No arg for -t option      # (this error is being printed by bash)

Solution

  • Several points here:

    # Note the leading ':'
    while getopts :ht: OPTION
    do
        case $OPTION in
            h)
                echo "Hi"
                ;;
            t)
                echo "You entered $OPTARG"
                if [[ ${OPTARG:0:1} == '-' ]]; then
                    echo "Invalid value $OPTARG given to -$OPTION" >&2
                    exit 1
                fi
                ;;
            :)  echo "$0: -$OPTARG needs a value" >&2; 
                exit 2 
                ;;
            \?) echo "$0: unknown option -$OPTARG" >&2; 
                exit 3
                ;;
        esac
    done
    

    The leading ':' on the option list allows us to do our own error handling. If an unknown option is supplied then OPTION is set to a ?. Note that in the case statement this has to be escaped (prefixed with a \), otherwise it would match any single character.

    If a value is not supplied to an option, then OPTION is set to a :. Unfortunately this does not help if someone does:

    ./x -t -h
    

    since the -h will be taken as the OPTARG to option -t. Hence the extra test.

    Notice that all the error messages go to standard-error (>&2). To halt the execution of the script we use exit followed by a number in the range 0-255. The only number with a specific meaning is zero, which means success. The numbers 1-255 can have any meaning that we choose, but all imply failure.

    Using your examples:

    ./x.sh -t -h
    You entered -h
    Invalid value -h given to -t
    
    ./x.sh -h -t aa
    Hi
    You entered aa
    
    ./x.sh -h -t
    Hi
    ./x.sh: -t needs a value
    
    ./x.sh -t tea -c
    You entered tea
    ./x.sh: unknown option -c