Bash getopt 不接受某些双破折号 (--) 字符

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

在传递 - 字符时使用以下 getopt 时出现奇怪的错误。这是代码示例和输出:

#!/bin/bash

function _echo()
{
  msg=""
  # 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

输出:

-- <--[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]

你可以看到上面传递给_echo函数的一些语句即使字符串被引用也有错误?如果要在 _echo 函数中传递长破折号 (-------),如何解决这个问题?

谢谢。

引用并不重要...调用 _echo --Hello 与调用 _echo "--Hello" 之间没有区别。在这两种情况下,_echo 函数都接收一个参数 --Hello。由于您只接受参数 -t,任何其他看起来像参数的东西都会导致错误。

getopt 手册页中描述了正确的处理方法:

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.

也就是说,如果你想传入一个参数,比如--Hello, 你需要这样调用 _echo

_echo -- --Hello

-- 告诉 getopt 后面的任何参数都不应该被解释为选项,即使它们恰好看起来像一个。

因此您脚本中的示例将如下所示:

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

这是许多命令行程序的通用约定。


如您所见,_echo 的实施存在问题。这是解析选项的典型结构 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  in
    (-t)   echo "got -t"
          shift
          ;;

    (--)  shift
          break
          ;;

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

    (*)   break
          ;;
    esac
  done

  msg=
  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"