Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why cant I have a space between option and optional argument using getopt?

Tags:

bash

getopt

When using getopt to parse commandline parameters you can put a space in between the option flag and the argument for required arguments but not for optional arguments. Optional arguments will only be parsed if they are right after the option.

TEMP=`getopt -o p:q:: -n 'mkqueue.sh' -- "$@"`

if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi

# Note the quotes around `$TEMP': they are essential!
eval set -- "$TEMP"

# Now go through all the options
while true ; do
    case "$1" in
        -p) echo "Option p, argument \`$2'" ; shift 2 ;;
        -q) 
            case "$2" in
                "") echo "Option q, no argument"; shift 2 ;;
                *)  echo "Option q, argument \`$2'" ; shift 2 ;;
            esac ;;
        --) shift ; break ;;
        *) echo "Internal error!" ; exit 1 ;;
    esac
done

(Based on this: http://software.frodo.looijaard.name/getopt/docs/getopt-parse.bash)

When I run the script without the optional argument it works:

./mkqueue.sh -p adfsa -q
Option p, argument `adfsa'
Option q, no argument

If I try to add the optional argument to -q with a space in between it doesnt work:

./mkqueue.sh -p adfsa -q sdfasdfa
Option p, argument `adfsa'
Option q, no argument

It works if you don't have a space in between the option and argument, even though required arguments work with the space:

./mkqueue.sh -p adfsa -qsdfasdfa
Option p, argument `adfsa'
Option q, argument `sdfasdfa'

Is there a fix for this?

like image 853
pdizz Avatar asked Oct 17 '14 18:10

pdizz


1 Answers

That limitation is documented in the manpage for getopt:

A simple short option is a `-' followed by a short option character. If the option has a required argument, it may be written directly after the option character or as the next parameter (ie. separated by whitespace on the command line). If the option has an optional argument, it must be written directly after the option character if present.

Although getopt allows "optional option arguments", they are generally considered to be a bad idea. The Posix Utility Syntax Guidelines, for example, include:

Guideline 7: Option-arguments should not be optional.

The basic reason for this guideline is that by convention the argument to a command-line option may be any string whatsoever. It might look like another option, for example. It might be the literal string --, which normally indicates the end of the option list. It might be an empty string. Anything.

The problem with "optional option arguments" is that the only way to know that an optional option argument is not provided is to recognize the following argument as either an option or --. But that means that the value of the optional argument cannot start with a -.

Alternatively, you can choose the solution taken by the getopt command-line utility, which is to require that the optional argument immediately follow the option, without an intervening space (that is, being in the same word). But in that case, the optional argument cannot be an empty string.

Rather than creating complicated rules for resolving these ambiguities, the simple solution -- recommended by Posix (and, with a lot less authority, by me) -- is to not allow option arguments to be optional. If there is a common value for a command-line option and you want to simplify the life of the user by not requiring it to be typed, then implement two different command-line options, one of which takes an argument and the other of which doesn't. Common techniques include using a lower-case character for the version without an argument, and the corresponding upper-case character for the version with an argument, or using a long option (--option) for that version.

For those who prefer dense and packed explanation, the Posix rationale explains that:

Guideline 7 allows any string to be an option-argument; an option-argument can begin with any character, can be - or --, and can be an empty string. For example, the commands pr -h -, pr -h --, pr -h -d, pr -h +2, and pr -h '' contain the option-arguments -, --, -d, +2, and an empty string, respectively. Conversely, the command pr -h -- -d treats -d as an option, not as an argument, because the -- is an option-argument here, not a delimiter.

like image 63
rici Avatar answered Dec 16 '22 04:12

rici