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

时间:2021-08-01 13:13:47

标签: bash getopt

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

#!/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

输出:

-- <--[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 函数中传递长破折号字符 (-------),您如何克服这个问题?

谢谢。

1 个答案:

答案 0 :(得分:1)

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

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

<块引用>

'--' 参数后的每个参数总是被解释为 非选项参数。如果环境变量 POSIXLY_CORRECT 是 设置,或者如果短选项字符串以 '+' 开头,则所有剩余 参数被解释为非选项参数 找到第一个非选项参数。

换句话说,如果你想传入一个像--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 $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"