使用 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 页面深处) 但它不管理在命令末尾给出选项的情况。
在这种情况下,这被认为是错误的,因为没有给出参数,getopts
将 opt
变量设置为 ':'(冒号)并将 OPTARG
设置为错误选项值。
因此,我们必须使用case $OPTARG
来管理“:”案例。
假设我们编写了一个包含三个选项的脚本:
a
: 无参数
b
: 带必填参数
v
:将 verbosity 设置为从 0
到 2
的值。默认值为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)