【问题标题】:Parsing getopts in bash在 bash 中解析 getopts
【发布时间】:2011-02-22 13:57:49
【问题描述】:

我有一个 bash 函数,我正在尝试使用 getopts,但遇到了一些麻烦。

该函数被设计为自行调用 (getch),带有可选的 -s 标志 (getch -s),或者之后带有可选的字符串参数(所以 getch mastergetch -s master 都是有效的)。

下面的 sn-p 是我的问题所在 - 它不是整个功能,但这是我关注的:

getch()
{
  if [ "$#" -gt 2 ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
    echo "Usage: $0 [-s] [branch-name]" >&2
    return 1
  fi

  while getopts "s" opt; do
    echo $opt # This line is here to test how many times we go through the loop
    case $opt in
      s) 
        squash=true
        shift
        ;;
      *) 
        ;;
    esac
  done
}

getch -s master 案例是奇怪发生的地方。上面应该吐出一次s,但相反,我得到了这个:

[user@host:git-repositories/temp]$ getch -s master
s
s
[user@host:git-repositories/temp]$

为什么解析-s opt 两次?

【问题讨论】:

  • 我很难重现这个问题。我将您的代码复制到一个文件中,并使用 -s master、-s -s -s 和任何其他愚蠢的东西运行它,并且打印时间不能超过 1 秒。
  • 抱歉,我也无法复制。这对我来说可以。将您的 echo $opt 更改为 echo "In getopts: $opt" 以使其与众不同,以防有其他东西与之呼应。
  • OPTIND=1放在getops循环之前。 $OPTIND 是参数列表中接下来由 getopts 解析的位置(当您完成 while 循环时,您应该执行 shift $((OPTIND-1)) 以“移走”那些已解析的参数)。如果您忽略将 OPTIND 重新设置为 1,那么下次您在当前 shell 中执行 getopts(例如:另一个函数)时,您将从 $OPTIND-th 参数开始解析,通常为空,使 getops 返回 false 和 " while" 直接退出,不解析参数。
  • 并且不要在 getops 循环内shift。相反,在done 之后,放置一个shift $((OPTIND -1)),以便移出getopts 解析的所有参数。

标签: bash function getopts


【解决方案1】:

【讨论】:

    【解决方案2】:

    尝试在您编写的函数之外解析选项。今天下午我又玩弄了一点。在解析函数中的选项而不是仅在脚本主体中时,我很难让它正常工作。

    否则,我真的不知道该告诉你什么。

    【讨论】:

      【解决方案3】:

      我也无法在运行 Bash 4 的 Ubuntu 10.4 机器或运行 Bash 3.2.17 的 MacOSX 机器上重现该问题。

      您的 shell 环境可能被早期的调试工作所污染。

      您是否尝试过从新的终端窗口开始?或者使用 'exec bash' 启动一个新的 shell 并再次尝试该功能。

      stefanl@ubuntu:~ $ getch()
      > {
      >   if [ "$#" -gt 2 ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
      >     echo "Usage: $0 [-s] [branch-name]" >&2
      >     return 1
      >   fi
      > 
      >   while getopts "s" opt; do
      >     echo $opt # This line is here to test how many times we go through the loop
      >     case $opt in
      >       s) 
      >         squash=true
      >         shift
      >         ;;
      >       *) 
      >         ;;
      >     esac
      >   done
      > }
      stefanl@ubuntu:~ $ getch -s master
      s
      

      【讨论】:

      • 按照您的建议,我尝试做一个新的子shell,并且成功了。一定是事先对我的环境做了什么……无论如何,感谢您的帮助!
      • 这种情况时有发生。调试脚本很容易陷入困境,而忘记您的环境可能会损坏。
      • (删除我错误地放入此答案而不是提问者帖子中的 cmets)