0

I am using getopt and want to have an option -l that takes an optional value. I am finding that when matching -l by itself with no argument value provided, I still have to use shift 2 rather than just one shift. What is going on and how does this happen?

opts=$( getopt -o "$shortopts" -l "$longopts" -n "${0##*/}" -- "$@" ) 
eval "set -- ${opts}"
while (( $# > 0 )); do
  case $1 in
    ("-l")
      case "$2" in
        (+([[:digit:]]))
          # matches -lNUM, optional argument value
          nl="$2"; shift 2 ;;
        (*)
          # matches -l, no argument value provided
          nl=1 ; shift ;;
        esac
        ;;
      ("--") shift ; break ;;
      (*) opt_error=1 ; break ;;
    esac
  done
cas
  • 78,579
Vera
  • 1,223

1 Answers1

2

If you look in man getopt under the OUTPUT section, you'll see that it says:

If the option takes an optional argument, but none was found, the next parameter will be generated but be empty in quoting mode, but no second parameter will be generated in unquoted (compatible) mode.

What this means is that (if you're not running it in compatibility mode, and there's little reason to do that for non-legacy scripts) getopt will generate an argument for that option, either empty or with the optional value, and add it to the argument list immediately after the option.

That means that there'll always be an argument following the option, so you'll always need to shift 2.

BTW, for optional args, you should probably either set nl to its default value before the while/case loop, or use parameter expansion with a default value. e.g.

nl="${2:-default_value}"

You should probably also test for both the short and long options in the same case statement, otherwise you'll unnecessarily duplicate code to handle both long & short variants. e.g.:

-l|--long) ... ;;
cas
  • 78,579