是否可以使用 GNU getopt 忽略未知的可选参数?
我有一个脚本 scriptA.sh,它有可选参数
--optA, --optB, --optC, --optD
。
我想编写一个包装器,wrapperA,带有两个可选参数,
--optX and --optY
,调用scriptA
。 但是,我不想在包装器内声明 scriptA 的所有可选参数。
特别是,如果在
wrapperA
内,我用 指定可选参数
getopt --longoptions optX:,optY:
来电
wrapperA --optX --optA --optB
返回错误
getopt: unknown option -- optA
GNU getopt 可以被迫忽略未知参数并将它们放在输出中的“--”之后吗?
不可能告诉 GNU getopt 忽略未知选项。如果您确实想要该功能,则必须编写自己的选项解析器。
这并不只是忽略未知选项那么简单。如何判断未知选项是否带有参数?
原始脚本的用法示例:
originalscript --mode foo source
这里
foo
是选项 --mode
的参数。而 source
是“非选项参数”(有时称为“位置参数”)。
包装脚本的用法示例:
wrapperscript --with template --mode foo source
wrapperscript
中的getopt如何知道它应该忽略--mode
和foo
?如果它只是忽略 --mode
那么 foo
将是第一个位置参数而不是 source
。
一个可能的解决方法是告诉包装脚本的用户在双破折号后编写用于原始脚本的所有选项 (
--
)。
wrapperscript --with template -- --mode foo source
按照惯例,双破折号标志着选项的结束。 GNU getopt 识别双破折号并停止解析并将其余部分作为位置参数返回。然后您可以将它们传递给原始脚本。
这种方法的最大缺点是,您必须教育用户将所有包装脚本选项放在前面,然后是双破折号,然后是所有原始脚本选项。这实际上保证了用户总是会出错。
我正在做类似的事情,发现这可以阻止 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
对于
getopt
,至少对于 util-linux-2.37.2 中的一个,可以忽略 STDERR 或可以使用 --quiet 标志:
$ getopt --quiet --options=c: --longoptions=component -- --component value --foo
--component -- 'value'
请注意,退出状态仍为 1,因为参数验证无法通过
getopt
完成,因为它不知道您要忽略哪种错误。
如果您只想忽略 stderr,请将
2>dev/null
附加到 while
的起始行,如下所示。我想你也可以用这个来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
好吧,我可以解决这个问题。这个想法涉及到在面对未知选项时摆弄
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))
部分请适应您自己的情况。该假设被证明是脆弱且非包容性的,但在这种情况下是有效的。另请注意,如果出现错误(缺少参数),它仍然会停止。
显然,这不是一种通用且干净的方法,但有助于克服找不到其他替代方案的情况。