MaXi32
MaXi32

Reputation: 668

Bash getopt does not accept some of the double dash (--) character

I got a weird error when using the following getopt when passing the - character. Here is the example of the code and the output:

#!/bin/bash

function _echo()
{
  msg="$1"
  # A sample getopt option with only t as short parameter
  # I put -q to silent error and use output based on getopt return status
  options=$(getopt -q -o t -- "$@")
  retval=$?
  if [ ${retval} -ne 0 ]; then
    echo "${msg} <--[this has error]"
  else
    echo "${msg} <--[this is ok]"
  fi
  echo ""
  eval set -- "${options}"
}

# Calling function _echo() without passing any option (sample):

_echo "--" # OK
_echo "Hello" # OK
_echo "Hello--" # OK
_echo "-" # OK
_echo "---------------" # Error
_echo "---" # Error
_echo "--Hello" #Error
_echo "-Hello" #Error

Output:

-- <--[this is ok]

Hello <--[this is ok]

Hello-- <--[this is ok]

- <--[this is ok]

--------------- <--[this has error]

--- <--[this has error]

--Hello <--[this has error]

-Hello <--[this has error]

You can see that some of the above statements passed to _echo function have errors even the strings are quoted ? How do you overcome this problem if you want to pass the long dash character (-------) inside the _echo function ?

Thanks.

Upvotes: 1

Views: 1103

Answers (1)

larsks
larsks

Reputation: 311526

Quoting doesn't matter...there's no difference between calling _echo --Hello vs calling _echo "--Hello". In both cases, the _echo function receives a single parameter, --Hello. Since you only accept the parameter -t, anything else that looks like a parameter is going to cause an error.

The correct way of handling this is described in the getopt man page:

Each parameter after a '--' parameter is always interpreted as a non-option parameter. If the environment variable POSIXLY_CORRECT is set, or if the short option string started with a '+', all remaining parameters are interpreted as non-option parameters as soon as the first non-option parameter is found.

In other words, if you want to pass in a parameter like --Hello, you need to call _echo like this:

_echo -- --Hello

The -- tells getopt that any following parameters should not be interpreted as options, even if they happen to look like one.

So the examples in your script would look like:

_echo "--" # OK
_echo "Hello" # OK
_echo "Hello--" # OK
_echo "-" # OK
_echo -- "---------------" # Error
_echo -- "---" # Error
_echo -- "--Hello" #Error
_echo -- "-Hello" #Error

This is a common convention for many command line programs.


As you spotted, there were problems with your implementation of _echo. Here's a typical structure for parsing options with getopt:

function _echo()
{
  options=$(getopt -q -o t -- "$@")
  if [ "$?" -ne 0 ]; then
    echo "ERROR: incorrect options in $@"
    return 1
  fi

  eval set -- "$options"
  while [ "$#" -gt 0 ]; do
    case $1 in
    (-t)   echo "got -t"
          shift
          ;;

    (--)  shift
          break
          ;;

    (-*)  echo "unknown option: $1"
          return 1
          ;;

    (*)   break
          ;;
    esac
  done

  msg=$1
  echo "message is: $msg"
}

# Calling function _echo() without passing any option (sample):

_echo "--"
_echo "Hello"
_echo "Hello--"
_echo "-"
_echo -- "---------------"
_echo -- "---"
_echo -- "--Hello"
_echo -- "-Hello"
_echo -t -- "-Hello"

Upvotes: 1

Related Questions