简体   繁体   English

bash中多次调用getopts

[英]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 $@

Revised example command line 修改后的示例命令行

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 in parseArgs but parseRemainingArgs will fail to parse the remaining args. 在这种情况下, -t将在parseArgs匹配,但是parseRemainingArgs将无法解析其余的args。 It works great when -t or -h is not given which matches in parseArgs . 当未给出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下运行它。

'Cannot reproduce' response “无法复制”响应

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 shbash的链接
  • 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)) . 其中, hshsvr4-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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM