[英]Multiple calls to getopts in bash
When this script is called 调用此脚本时
test.sh -a 1 -b 2 -c 3
output is : -a 1 -b 2 1
输出为:
-a 1 -b 2 1
I was expecting parseRemainingArgs
to parse and print all arguments. 我期待
parseRemainingArgs
解析并打印所有参数。 As you can see all the arguments are passed properly to parseRemainingArgs
as seen in first line of output, but it parses only the first argument. 如您所见,所有参数都正确地传递到
parseRemainingArgs
如输出的第一行所示,但它仅解析第一个参数。
I set the OPTIND as well but that also didn't help. 我也设置了OPTIND,但这也无济于事。
Need help in identifying what is wrong with this and how to fix that. 在确定问题出在哪里以及如何解决该问题方面需要帮助。
Tried all available answers which google provides but none of them solves this problem. 尝试了google提供的所有可用答案,但没有一个可以解决此问题。
#!/bin/sh
parseRemainingArgs()
{
echo $@
OPTIND=1
while getopts :ha:b:c: o;
do
case "$o" in
h) echo "Print help";;
a) FIRST_ARG="$OPTARG";;
b) SECOND_ARG="$OPTARG";;
c) THIRD_ARG="$OPTARG";;
\?) ;;
esac
done
echo $FIRST_ARG $SECOND_ARG $THIRD_ARG
}
parseArgs()
{
AllArgs=$@
while getopts :ht: o;
do
case "$o" in
t) TARGET="$OPTARG";;
h) HELP="yes";;
\?) ;;
esac
done
shift $(($OPTIND - 1))
parseRemainingArgs $AllArgs
}
parseArgs $@
Chhaba observed : Chhaba 观察到 :
To get the problem can you please test your script with the following arguments
为了解决这个问题,可以请您使用以下参数测试脚本
gomod.sh -ta -a 1 -b 2 -c 3
In this case
-t
will match inparseArgs
butparseRemainingArgs
will fail to parse the remaining args.在这种情况下,
-t
将在parseArgs
匹配,但是parseRemainingArgs
将无法解析其余的args。 It works great when-t
or-h
is not given which matches inparseArgs
.当未给出
parseArgs
中匹配的-t
或-h
时,它的效果很好。
OK; 好; that's what I'd expect from the script I used (see the script below in the "'Cannot reproduce' response" section — it is a mild extension of what's in the question).
这就是我使用的脚本所期望的(请参见下面的“'无法重现'响应”部分中的脚本,这是对问题内容的温和扩展)。 From
bash
, I get: 从
bash
,我得到:
$ bash gomod.sh -t a -a 1 -b 2 -c 3
Initial arguments: -t a -a 1 -b 2 -c 3
Doing nothing
OPTIND = 4
Residual arguments: 1 -b 2 -c 3
Parsing Remaining: -t a -a 1 -b 2 -c 3
Ignoring error
a1: a2: a3
$
It's a consequence of you setting AllArgs
at the start of parseArgs
. 这是因为您在
parseArgs
的开始处设置了AllArgs
的结果。 It doesn't change as you parse the arguments in "$@"
in parseArgs
, so you pass the original argument list to parseRemainingArgs
, as shown in the diagnostic output. 当您在
parseArgs
解析"$@"
中的参数时,它不会改变,因此您将原始参数列表传递给parseRemainingArgs
,如诊断输出所示。 In parseRemainingArgs
, -t
is not an option, so the loop returns an error on the -t
(hence Ignoring error
), and then exits because a
is not an option. 在
parseRemainingArgs
, -t
不是选项,因此循环会在-t
上返回错误(因此Ignoring error
),然后退出,因为a
不是选项。
You can get more output from: 您可以从以下获得更多输出:
$ bash gomod.sh -t -a 1 -b 2 -c 3
Initial arguments: -t -a 1 -b 2 -c 3
OPTIND = 3
Residual arguments: 1 -b 2 -c 3
Parsing Remaining: -t -a 1 -b 2 -c 3
Ignoring error
a1: 1 a2: 2 a3 3
$
It ignores the -t
error in parseRemainingArgs
and then processes each of -a
, -b
and -c
with the corresponding argument. 它忽略
parseRemainingArgs
的-t
错误,然后使用相应的参数处理-a
, -b
和-c
每-a
。
Alternatively, you could modify the script, replacing the invocation of parseRemainingArgs
with: 或者,您可以修改脚本,将
parseRemainingArgs
的调用替换为:
parseRemainingArgs "$@"
You can then run it like this, for example, and get the output shown: 例如,您可以像这样运行它,并显示如下输出:
$ bash gomod.sh -t antelope -- -a 1 -b 22 -c 333
Initial arguments: -t antelope -- -a 1 -b 22 -c 333
OPTIND = 4
Residual arguments: -a 1 -b 22 -c 333
Parsing Remaining: -a 1 -b 22 -c 333
a1: 1 a2: 22 a3 333
$
Note that replacing the --
with nothing, or with abelone
(or any other non-option) does not work as you'd want. 请注意,一无所获或用
abelone
(或其他任何非选项)代替--
都无法正常工作。
You could still add a lot more debugging to make it easier to understand, or run it under bash -x
. 您仍然可以添加更多调试信息,以使其更易于理解,或者在
bash -x
下运行它。
I'm not sure what your problem is any more. 我不确定您的问题了。 I've run a slightly modified version of your script — more diagnostics and using back-quotes and
expr
to calculate the shift (because some of the shells I tested with don't support the $((…))
arithmetic notation). 我已经运行了稍微修改过的脚本版本-进行了更多诊断,并使用了反引号和
expr
来计算偏移量(因为我测试过的某些shell不支持$((…))
算术符号)。 The code was: 代码是:
#!/bin/sh
parseRemainingArgs()
{
echo "Parsing Remaining:" "$@"
OPTIND=1
while getopts :ha:b:c: o
do
case "$o" in
h) echo "Print help";;
a) FIRST_ARG="$OPTARG";;
b) SECOND_ARG="$OPTARG";;
c) THIRD_ARG="$OPTARG";;
\?) echo "Ignoring error";;
esac
done
echo a1: $FIRST_ARG a2: $SECOND_ARG a3 $THIRD_ARG
}
parseArgs()
{
AllArgs=$@
echo "Initial arguments:" "$@"
while getopts :ht: o
do
case "$o" in
t) TARGET="$OPTARG";;
h) HELP="yes";;
\?) echo "Doing nothing";;
esac
done
#shift $(($OPTIND - 1))
echo "OPTIND = $OPTIND"
shift `expr $OPTIND - 1`
echo "Residual arguments:" "$@"
parseRemainingArgs $AllArgs
}
parseArgs "$@"
The shells tested were: 测试的外壳是:
sh
— a link to bash
sh
— bash
的链接 bash
dash
ksh
— Korn shell ksh
— Korn外壳 zsh
hsh
— Heirloom shell (close to Bourne shell) hsh
—传家宝外壳(接近伯恩外壳) svr4-sh
— Unix System V Release 4 (slightly souped up Bourne shell) svr4-sh
— Unix System V发行版4(稍微加重了Bourne shell) Of these, hsh
and svr4-sh
did not accept shift $(($OPTIND - 1))
. 其中,
hsh
和svr4-sh
不接受shift $(($OPTIND - 1))
。 I'm slightly surprised the Heirloom shell recognizes getopts
at all. 我很惊讶Heirloom shell完全识别出
getopts
。
The script was called gomod.sh
, and the output I got was: 该脚本称为
gomod.sh
,我得到的输出是:
$ for shell in sh bash dash ksh zsh hsh svr4-sh
> do
> boxecho $shell
> $shell gomod.sh -a 1 -b 2 -c 3
> echo
> done
********
** sh **
********
Initial arguments: -a 1 -b 2 -c 3
Doing nothing
OPTIND = 2
Residual arguments: 1 -b 2 -c 3
Parsing Remaining: -a 1 -b 2 -c 3
a1: 1 a2: 2 a3 3
**********
** bash **
**********
Initial arguments: -a 1 -b 2 -c 3
Doing nothing
OPTIND = 2
Residual arguments: 1 -b 2 -c 3
Parsing Remaining: -a 1 -b 2 -c 3
a1: 1 a2: 2 a3 3
**********
** dash **
**********
Initial arguments: -a 1 -b 2 -c 3
Doing nothing
OPTIND = 2
Residual arguments: 1 -b 2 -c 3
Parsing Remaining: -a 1 -b 2 -c 3
a1: 1 a2: 2 a3 3
*********
** ksh **
*********
Initial arguments: -a 1 -b 2 -c 3
Doing nothing
OPTIND = 2
Residual arguments: 1 -b 2 -c 3
Parsing Remaining: -a 1 -b 2 -c 3
a1: 1 a2: 2 a3 3
*********
** zsh **
*********
Initial arguments: -a 1 -b 2 -c 3
Doing nothing
OPTIND = 2
Residual arguments: 1 -b 2 -c 3
Parsing Remaining: -a 1 -b 2 -c 3
a1: 1 -b 2 -c 3 a2: a3
*********
** hsh **
*********
Initial arguments: -a 1 -b 2 -c 3
Doing nothing
OPTIND = 2
Residual arguments: 1 -b 2 -c 3
Parsing Remaining: -a 1 -b 2 -c 3
a1: 1 a2: 2 a3 3
*************
** svr4-sh **
*************
Initial arguments: -a 1 -b 2 -c 3
Doing nothing
OPTIND = 2
Residual arguments: 1 -b 2 -c 3
Parsing Remaining: -a 1 -b 2 -c 3
a1: 1 a2: 2 a3 3
$
boxecho
is a trivial script that echoes its arguments inside a box of stars: boxecho
是一个简单的脚本,它在一个星星盒内回显其参数:
echo "** $@ **" | sed -e h -e 's/./*/g' -e p -e x -e p -e x
I hadn't modified it since 1998; 自1998年以来,我从未进行过修改。 I don't often have a subdirectory
s
with a subdirectory inside that contains a file g
, so the absence of quotes around the s/./*/g
hadn't ever bit me, but I've fixed the script above (and in my bin
directory). 我通常不会在子目录
s
有一个包含文件g
的子目录,因此在s/./*/g
周围没有引号并没有引起我的注意,但是我已经修复了上面的脚本(和在我的bin
目录中)。 There are other ways of writing the sed
too; 编写
sed
也有其他方法。 this does, however, work. 但这确实有效。
It is worth noting that the use of getopts
in the parseRemainingArgs
function works with the full set of arguments originally passed to the command, despite the implication that it is working on 'the remaining arguments'. 值得注意的是,尽管暗示它正在处理“其余参数”,但在
parseRemainingArgs
函数中使用getopts
可以与最初传递给命令的全套参数一起使用。 You'd pass "$@"
to the function if it were to process the as yet unprocessed arguments. 如果要处理尚未处理的参数,则将
"$@"
传递给该函数。 It would also run into 'end of arguments' immediately unless you have a GNU getopts
functionality without POSIXLY_CORRECT set in the environment since the first such argument would be 1
which is not an option and would terminate the getopts
processing. 除非您在环境中未设置POSIXLY_CORRECT的情况下具有GNU
getopts
功能,否则它也会立即遇到“参数结尾”,因为第一个此类参数为1
这不是选项),将终止getopts
处理。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.