Linux GNU getopt:忽略未知可选参数?

12

如何使用GNU getopt忽略未知的可选参数?

我有一个脚本scriptA.sh,它有可选参数--optA、--optB、--optC和--optD。

我想写一个包装器wrapperA,它有两个可选参数--optX和--optY,并调用scriptA。但是,我不想在包装器中声明所有scriptA的可选参数。

特别地,如果我在wrapperA中指定可选参数:

getopt --longoptions optX:,optY:

电话

wrapperA --optX --optA --optB

返回错误

getopt: unknown option -- optA

GNU getopt是否可以被强制忽略未知参数并将它们放置在“--”之后的输出中?

5个回答

6

无法告诉GNU getopt忽略未知选项。如果您真的需要该功能,您将不得不编写自己的选项解析器。

忽略未知选项并不像看起来那么简单。如何确定未知选项是否需要参数?

原始脚本的使用示例:

originalscript --mode foo source

这里foo是选项--mode的参数。而source是一个“非选项参数”(有时也称为“位置参数”)。

包装脚本的示例用法:

wrapperscript --with template --mode foo source
wrapperscript中的getopt如何知道它应该忽略与foo一起的--mode?如果只忽略--mode,则originalscript将把foo作为第一个位置参数。
一个可能的解决方法是告诉您的包装脚本用户在双短划线(--)后编写所有用于原始脚本的选项。按照惯例,双短划线表示选项结束。GNU getopt会识别双短划线并停止解析,并将其余部分作为位置参数返回。
另请参见:http://wiki.bash-hackers.org/dict/terms/end_of_options

谢谢您的回复。在我的情况下,双破折号终止选项列表是可行的。至于忽略未知选项,我理解您的观点-这并不像看起来那么简单。我的初始想法是将所有未知选项推到 getopt 输出中的“--”后面(--with 模板--模式 foo source)。但是,只有在随后的参数处理被移交给原始脚本时,这才有效。正如您所说,包装脚本无法知道原始脚本的参数是否需要参数。 - user3830744
有类似的问题,双破折号很好用。 - Andrei LED

1

我曾经遇到类似的问题,发现以下方法可避免getopt错误干扰。基本上就是将错误信息直接丢弃。

while getopts "i:s:" opt > /dev/null 2>&1; do
    case $opt in
      i)
        END=$OPTARG
      ;;
    esac
done
./innerscript $*

$ ./blah.sh -s 20140503 -i 3 -a -b -c


如果缺少的参数使用了 OPTARG,则会出现这种情况。https://gist.github.com/cirosantilli/2a803442add75e0f1e164cde183999d3 GNU Bash 4.3.48。 - Ciro Santilli OurBigBook.com
1
如果在有效选项之前传递无效选项,则此方法也会出错。 - trysis
这个问题特指于 'getopt' 而不是内置的 'getopts'。 - trash80

0
对于getopt,至少对于util-linux-2.37.2中的一个版本,可以忽略标准错误输出或使用--quiet选项:
$ getopt --quiet --options=c: --longoptions=component -- --component value --foo
--component -- 'value'

请注意,退出状态仍将为1,因为无法通过getopt对参数进行验证,也无法知道您想要忽略哪种类型的错误。

-2

如果你想忽略 stderr 的输出,只需在 while 循环的起始行附加 2>dev/null 即可。我认为你也可以将其用于 getopt

while getopts "a:p:" opt 2>/dev/null
do
    case $opt in
      \?)
        echo "any error comment you want" 1>&2
        exit 1
        ;;
    esac
done

这个问题是关于 'getopt' 而不是内置的 'getopts'。 - trash80

-2

嗯,我可以解决这个问题。这个想法涉及到在遇到未知选项时调整OPTIND,以便通过getopts继续解析。因此,我们需要保持解析的位置,以便相应地调整OPTIND

local parse_index=1 # initialize to cater for the first option coming out unknown
while getopts ':m:t:r:u:p:' opt; do
  case $opt in
    m) build_module="$OPTARG"
       parse_index=$OPTIND
       ;;
    t) build_tag="$OPTARG"
       parse_index=$OPTIND
       ;;
    r) container_registry="$OPTARG"
       parse_index=$OPTIND
       ;;
    u) registry_username="$OPTARG"
       parse_index=$OPTIND
       ;;
    p) registry_password="$OPTARG"
       parse_index=$OPTIND
       ;;
    :) echo "Option -$OPTARG requires an argument" >/dev/stderr
       ;;
   \?) echo "Unknown option: -$OPTARG"
       ((OPTIND = $parse_index + 2))    # fool `getopts` to continue parsing
       parse_index=$OPTIND      # adjust to cater for successive unknown options
       ;;
  esac
done

我使用了一种假设,即遇到未知选项后面会跟着一个参数,因此部分代码((OPTIND = $parse_index + 2))需要根据您自己的情况进行调整。这种假设证明是脆弱和不全面的,但在这些情况下仍然有效。另外请注意,在出现错误(缺少参数)的情况下,它仍然会停止执行。

显然,这不是一种通用和干净的方法,但帮助克服了没有其他替代方案的情况。


这个问题特指于 'getopt' 而不是内置的 'getopts'。 - trash80

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接