Bash 如何使用getopts忽略无效参数并继续解析?
我有以下简单的代码:Bash 如何使用getopts忽略无效参数并继续解析?,bash,shell,syntax,arguments,getopts,Bash,Shell,Syntax,Arguments,Getopts,我有以下简单的代码: #!/usr/bin/env bash while getopts :f arg; do case $arg in f) echo Option $arg specified. ;; *) echo Unknown option: $OPTARG. ;; esac done 它可以在简单的场景中工作,例如: $ ./test.sh -f Option f specified. $ ./test.sh -a -f Unknown option: a.
#!/usr/bin/env bash
while getopts :f arg; do
case $arg in
f) echo Option $arg specified. ;;
*) echo Unknown option: $OPTARG. ;;
esac
done
它可以在简单的场景中工作,例如:
$ ./test.sh -f
Option f specified.
$ ./test.sh -a -f
Unknown option: a.
Option f specified.
但是,它不适用于以下情况:
$ ./test.sh foo -f
$ ./test.sh -a abc -f
Unknown option: a.
如何修复上面的代码示例以支持无效参数?似乎
getopts
只要找到某个未知的非选项参数(abc
),就会退出循环
通过将getopts
循环包装到另一个循环中,我找到了以下解决方法:
#!/usr/bin/env bash
while :; do
while getopts :f arg; do
case $arg in
f)
echo Option $arg specified.
;;
*)
echo Unknown option: $OPTARG.
;;
esac
done
((OPTIND++))
[ $OPTIND -gt $# ] && break
done
然后跳过无效参数,并在达到最大参数时中断循环
输出:
$ ./test.sh abc -f
Option f specified.
$ ./test.sh -a abc -f
Unknown option: a.
Option f specified.
下面是一个非常非通用的解决方案,它有自己的问题,但至少在我自己的用例中是有效的。我怀疑OP的问题只是展示问题的一个简单例子,所以它可能不适用于“真正”的问题
本主题帮助我找到了在尝试检测命令行上是否存在特定参数时所寻找的答案。我以不同的方式实现了它,所以我想我会分享我的解决方案。 代码中包含了注释,希望有助于理解此实现。 出于调试目的,还包括一些注释掉的行
###############################################################################
#
# Convenience method to test if a command line option is present.
#
# Parameters:
# $1 - command line argument to match against
# $2 - command line parameters
#
# Example:
# is_cmd_line_option_present "v" "$@"
# check if the -v option has been provided on the command line
#
###############################################################################
function is_cmd_line_option_present()
{
_iclop_option="$1"
# remove $1 from the arguments (via the shift command) to this method before searching for it from the actual command line
shift
# Default the return value to zero
_iclop_return=0
# Don't need to increment OPTIND each time, as the getopts call does that for us
for (( OPTIND=1; OPTIND <= $#; ))
do
# Use getopts to parse each command line argument, and test for a match
if getopts ":${_iclop_option}" _iclop_option_var; then
if [ "${_iclop_option_var}" == "${_iclop_option}" ]; then
_iclop_return=1
# else
# (>&2 echo -e "[Std Err]: is_cmd_line_option_present - Option discarded _iclop_option_var: [${_iclop_option_var}]")
fi
else
# (>&2 echo -e "[Std Err]: is_cmd_line_option_present - Unknown Option Parameter _iclop_option_var: [${_iclop_option_var}]")
# Need to increment the option indicator when an option is found that isn't listed as an expected option, as getopts won't do this for us.
((OPTIND++))
fi
done
# (>&2 echo -e "[Std Err]: is_cmd_line_option_present end - _iclop_return: [${_iclop_return}]")
return $_iclop_return;
}
###############################################################################
#
#测试是否存在命令行选项的简便方法。
#
#参数:
#$1-要匹配的命令行参数
#$2-命令行参数
#
#例如:
#命令行选项是否为“v”“$@”
#检查命令行上是否提供了-v选项
#
###############################################################################
函数为命令行选项当前()
{
_iclop_选项=“$1”
#在从实际命令行搜索$1之前,请(通过shift命令)从此方法的参数中删除$1
转移
#默认返回值为零
_iclop_返回=0
#不需要每次递增OPTIND,因为getopts调用为我们这样做
对于((OPTIND=1;OPTIND&2 echo-e“[Std Err]:是否存在命令行选项?选项是否已丢弃?选项是否变量:[${u iclop\u option\u var}]))
fi
其他的
#(>&2 echo-e“[Std Err]:是否存在命令行选项-未知选项参数{u iclop\u option\u var:[${u iclop\u option\u var}]”)
#当发现一个选项没有作为预期选项列出时,需要增加选项指示符,因为getopts不会为我们这样做。
((OPTIND++)
fi
完成
#(>&2 echo-e“[Std Err]:is_cmd_line_option_present end-_iclop_return:[${u iclop_return}]”)
退货$\u iclop\u退货;
}
什么是“支持无效参数”?getopts
在第一个非选项处停止解析(例如foo
或abc
)。您想让它做什么?不要这样做并解析所有内容?为了支持无效参数,尽管指定了未知参数,-f
仍然可以识别-abc-f
,但一旦发现无效参数,getopts
似乎正在停止处理。它在第一个非选项参数(即,abc
)处停止。例如,-a-a-a-f
将打印四次unknown。@EtanReisner在我看来,它停止是非常奇怪的。实际上,我需要它来处理我的更扩展的脚本,它涉及多次调用getopts
(但我不想让它变得复杂)。因此,第一次调用处理所有已知的选项,进一步调用只检查特定的参数,但它们失败,因为它们无法识别以前的参数(我在进一步调用时不关心这些参数)。同样,未知选项不是问题。非选项参数(不以-
开头的参数)是“问题”。在第一个非选项参数上停止是POSIX指定的行为。这对您来说只是一个问题,因为您正在以自己的方式解析相同的参数以寻找不同的有效选项。如果您只是告诉每个getopts调用有关每个参数的信息(但实际上只对您关心的参数执行任何操作)您不应该有问题。-a
不是问题。非选项值是。从示例中删除foo
和abc
,它们就会起作用(与原始示例一样)。这就是getopts
的功能。在这些示例中,您是否真正关心abc
值?因为这个双循环意味着您必须再次手动遍历参数并手动查找它(通过自己模拟getopts
逻辑)如果是的话。@EtanReisner我不关心未知的参数,比如当时的abc
,因为我可以在脚本的不同位置再次读取它。更普遍的做法是在while循环中增加params,然后检查params是否等于“-[aA zZ]”形式的$@中的子字符串数与“循环中的循环”选项相比,我更喜欢这个选项,而且它相当直截了当。
###############################################################################
#
# Convenience method to test if a command line option is present.
#
# Parameters:
# $1 - command line argument to match against
# $2 - command line parameters
#
# Example:
# is_cmd_line_option_present "v" "$@"
# check if the -v option has been provided on the command line
#
###############################################################################
function is_cmd_line_option_present()
{
_iclop_option="$1"
# remove $1 from the arguments (via the shift command) to this method before searching for it from the actual command line
shift
# Default the return value to zero
_iclop_return=0
# Don't need to increment OPTIND each time, as the getopts call does that for us
for (( OPTIND=1; OPTIND <= $#; ))
do
# Use getopts to parse each command line argument, and test for a match
if getopts ":${_iclop_option}" _iclop_option_var; then
if [ "${_iclop_option_var}" == "${_iclop_option}" ]; then
_iclop_return=1
# else
# (>&2 echo -e "[Std Err]: is_cmd_line_option_present - Option discarded _iclop_option_var: [${_iclop_option_var}]")
fi
else
# (>&2 echo -e "[Std Err]: is_cmd_line_option_present - Unknown Option Parameter _iclop_option_var: [${_iclop_option_var}]")
# Need to increment the option indicator when an option is found that isn't listed as an expected option, as getopts won't do this for us.
((OPTIND++))
fi
done
# (>&2 echo -e "[Std Err]: is_cmd_line_option_present end - _iclop_return: [${_iclop_return}]")
return $_iclop_return;
}