使用 getopts 读取作为最终位置放置的一个可选参数

Posted

技术标签:

【中文标题】使用 getopts 读取作为最终位置放置的一个可选参数【英文标题】:Using getopts to read one optional parameter placed as final place 【发布时间】:2015-05-04 18:33:52 【问题描述】:

我编写了一个 bash 脚本,它采用灵活数量的参数,现在我想为每个参数添加一个可选参数 (-l)。

我目前难以获得所需的行为。

我希望以下所有内容都能正确执行:

./Script.sh arg1 arg2 arg3 -l opt 
./Script.sh arg1 arg2 arg3
./Script.sh arg1 arg2 arg3 arg4 -l opt
./Script.sh arg1 arg2 arg3 arg4 arg5

问题是不能设置$OPTIND。 如果 -l opt 放在第一个参数之前,则以下循环有效。

while getopts ":l:" option
do
    case "$option" in
        t) 
            F_NAME=$OPTARG 
            ;;
    esac
done
shift $((OPTIND - 1))

但是,必须将可选的-l 作为最后一个参数。 实现这一目标的最简单方法是什么?

【问题讨论】:

Optional option argument with getopts的可能重复 【参考方案1】:

这是我发现的一个技巧,可以通过 getopts 使用带有可选参数的参数。

Jan Schampera 在 bash-hackers.org 上给出了管理可选参数在命令中的情况的方法:

  if [[ $OPTARG = -* ]]; then
    ((OPTIND--))
    continue
  fi

(见:http://wiki.bash-hackers.org/howto/getopts_tutorial 页面深处) 但它不管理在命令末尾给出选项的情况。

在这种情况下,这被认为是错误的,因为没有给出参数,getoptsopt 变量设置为 ':'(冒号)并将 OPTARG 设置为错误选项值。 因此,我们必须使用case $OPTARG 来管理“:”案例。

假设我们编写了一个包含三个选项的脚本:

a : 无参数 b : 带必填参数 v :将 verbosity 设置为从 02 的值。默认值为0,当使用-v 无参数或错误值调用脚本时使用预设值。

代码如下:

#!/bin/bash

VERBOSITY=0 # default verbosity set to 0
PRESET_VERBOSITY=1 # preset verbosity when asked

while getopts :ab:v: opt; do
  case $opt in
    a)
      echo "manage option a"
    ;;
    b)
      echo "manage option b with value '$OPTARG'"
    ;;
    v)
      if [[ $OPTARG = -* ]]; then # Jan Schampera reply
        echo "set verbosity to PRESET (no value given, not last position)"
        VERBOSITY=$PRESET_VERBOSITY
        ((OPTIND--))
        continue
      fi

      if [[ "$OPTARG" =~ ^[0-2]$ ]]; then
        echo "set verbosity to $OPTARG (good value given)"
        VERBOSITY=$OPTARG
      else
        echo "set verbosity to PRESET (bad value given)"
        VERBOSITY=$PRESET_VERBOSITY
      fi
    ;;
    :)
      case $OPTARG in
        v)
          echo "set verbosity to PRESET (no value given, last option)"
          VERBOSITY=$PRESET_VERBOSITY
        ;;
      esac
    ;;
    \?)
      echo "WTF!"
    ;;
  esac
done

echo "**verbosity is set to $VERBOSITY**"

【讨论】:

【参考方案2】:

getopts 符合 posix-standard 命令行语法,其中标志选项位于首位。所以对于非标准的情况使用起来不太方便。

但是,您可能拥有getopt(1) 的 Gnu 实现(请参阅man 1 getopt),它可以处理置换选项标志以及长选项。但是,它的界面并不简单。

或者你可以自己解释这个论点。

for ((i=1; i<=$#; ++i)); do
  if [[ $!i == "-l" ]]; then
    ((++i))
    OPT_L=$!i
  else
    # handle the argument (in "$!i]")
  fi
done

(注意:如果-l 出现在参数列表的末尾,则上述内容不会引发错误;它只是将选项值设置为空字符串。如果这不合适,则可能不合适,然后插入一些错误检查。)

【讨论】:

基本上,因为标志选项是第一位的,所以更适合将 otp 参数作为第一个传递?您的解决方案可能可以满足要求,但我不确定 else if 之间的“处理参数”部分是否可以标准化以满足每种可能的情况,不是吗? @SnP:没错;那个小小的 bash sn-p 并不是通用的。我个人只是使​​用 getopts 并将选项参数放在首位,但getopt 是通用解决方案(如果您有 Gnu 版本),这就是为什么我将其放在答案中。

以上是关于使用 getopts 读取作为最终位置放置的一个可选参数的主要内容,如果未能解决你的问题,请参考以下文章

如何在你的 shell 中使用互斥标志并添加一个可选参数标志(使用 getopts)

让 Dragula 显示悬停在元素上的放置位置

如何在 bash 中结合 getopts 和位置参数? [复制]

shell 脚本参数解析之 getopt getopts

读取 PDF 表单文件并返回可填写的字段坐标和字段名称

Unity - 在鼠标点击的位置放置对象