0

I have the following function and would like to look into how options with optional values can be set up using getopt.

Would like to have -w taking on default values

region -w -- "Text"

And -w 1 that takes the optional numeric value.

region -w 1 -- "Text"

The function is here

region ()
{
  # Process command line options
  shortopts="hw::"
  longopts="help,version,warning:"

  opts=$(getopt -o "$shortopts" -l "$longopts"  \
            -n "$(basename $0)" -- "$@")
  if [ $? -eq 0 ]; then
    eval "set -- ${opts}"
    while [ $# -gt 0 ]; do
      case "$1" in
      -h|-\?|--help)
        printf "%s\n" "Todo."
        shift
        break
        ;;
      -w|--warning)
        case "$2" in
          "1") local -r warn="first";  shift 2  ;;
            *) local -r warn="all";    shift 2  ;;
         esac
         local -r f=1
         ;;
      --)
         local -r f=1
         shift
         break
         ;;
      esac
    done
  else
    shorthelp=1 # getopt returned (and reported) an error.
  fi
    
}
2
2

You're probably not going to like this answer: for providing an arg to an option that optionally takes a arg, you're not allowed to use a space:

$ getopt -o 'w::' -- -w -- arg
 -w '' -- 'arg'

$ getopt -o 'w::' -- -w 1 -- arg
 -w '' -- '1' 'arg'

$ getopt -o 'w::' -- -w1 -- arg
 -w '1' -- 'arg'

Similarly, for option long argument, you must use =

$ getopt -o '' -l 'warning::' -- --warning -- arg
 --warning '' -- 'arg'

$ getopt -o '' -l 'warning::' -- --warning 1 -- arg
 --warning '' -- '1' 'arg'

$ getopt -o '' -l 'warning::' -- --warning=1 -- arg
 --warning '1' -- 'arg'

From the man page:

A simple short option is a '-' followed by a short option character[...] If the option has an optional argument, it must be written directly after the option character if present.

A long option normally begins with '--' [...] If the option has an optional argument, it must be written directly after the long option name, separated by '=', if present (if you add the '=' but nothing behind it, it is interpreted as if no argument was present; this is a slight bug, see the BUGS).


Just a code review comment about code layout: in an if-else-fi construct, put the short branch first. Here, by the time I get to else, I have to scan up to remember what the if condition was.

That also lets you write in an "assertion" style and out-dent the "main" code of the function:

region ()
{
  # Process command line options
  shortopts="hw::"
  longopts="help,version,warning:"

  opts=$(getopt -o "$shortopts" -l "$longopts"  \
            -n "$(basename $0)" -- "$@")
  if [ $? -ne 0 ]; then
    shorthelp=1 # getopt returned (and reported) an error.
    return
  fi

  eval "set -- $opts"
  # ...

Also, you can check the exit status directly and still assign to the variable (I'm also removing the basename call here)

  if ! opts=$(getopt -o "$shortopts" -l "$longopts" -n "${0##*/}" -- "$@")
  then
    shorthelp=1 # getopt returned (and reported) an error.
    return
  fi

With -w I set level=1. Otherwise, for -wNUM I set level=NUM

  local level=0
  #...
      case "$1" in
      -w|--warning)
         level=${2:-"1"}
         ;;

That uses the ${var:-default} form of parameter expansion.

3
  • I can deal with your answer. Was more interested in figuring out how the optional argument for -w could be specified or not. – Pietru Jul 22 at 19:10
  • Would like -w to work like this. With -w I set level=1. Otherwise, for -wNUM I set level=NUM. – Pietru Jul 23 at 8:21
  • Am scrutinising tho source code for getopt, when an option accepts an argument optionally. If the user does not supply the optional argument value, it looks like a null argument value is returned d->optarg = NULL;. Does this mean that me get '' for the argument value in such case of no optianal argument value being passed? – Pietru Jul 23 at 9:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.