调用此脚本时
test.sh -a 1 -b 2 -c 3
输出为:
-a 1 -b 21
我希望parseRemainingArgs解析并打印所有参数。
正如您所看到的,所有参数都被正确地传递到parseRemainingArgs中,如输出的第一行所示,但它只解析第一个参数。
我也设置了optind,但这也没有帮助。
需要帮助来确定这是什么问题以及如何解决。
尝试了谷歌提供的所有可用答案,但没有一个能解决这个问题。

#!/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 $@

最佳答案

修改的示例命令行
Chhabaobserved
要解决这个问题,可以用以下参数测试脚本吗

gomod.sh -t a -a 1 -b 2 -c 3

在这种情况下,-t将在parseArgs中匹配,但parseRemainingArgs将无法解析其余的参数。当-t-h中没有指定匹配项时,它工作得很好。
好的;这就是我所使用的脚本所期望的(请参阅下面“‘无法重现’响应”部分的脚本——它是问题的一个温和扩展)。从parseArgs,我得到:
$ 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
$

这是在bash开始时设置AllArgs的结果。当您解析parseArgs中的参数时,它不会改变,因此您将原始参数列表传递给"$@",如诊断输出中所示。在parseArgs中,parseRemainingArgs不是一个选项,所以循环在parseRemainingArgs(因此-t)上返回一个错误,然后退出,因为-t不是一个选项。
您可以从以下位置获得更多输出:
$ 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
$

它忽略Ignoring error中的a错误,然后使用相应的参数处理-tparseRemainingArgs-a中的每一个。
或者,您可以修改脚本,将对-b的调用替换为:
parseRemainingArgs "$@"

例如,您可以这样运行它,并获得如下输出:
$ 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
$

请注意,将-c替换为Nothing或parseRemainingArgs(或任何其他非选项)并不能按您的要求工作。
您仍然可以添加更多的调试以使其更易于理解,或者在--下运行它。
“无法复制”响应
我不知道你还有什么问题。我运行了一个稍微修改过的脚本版本-更多的诊断,并使用反引号和abelone来计算移位(因为我使用的一些shell不支持bash -x算术符号)。代码是:
#!/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 "$@"

测试的炮弹是:
expr-指向$((…))的链接
sh
bash
bash-科恩壳牌
dash
ksh-传家宝外壳(接近伯恩外壳)
zsh-unix系统v第4版(略微增强了bourne shell)
其中,hshsvr4-sh不接受hsh。我有点惊讶传家宝的外壳竟然能认出。
脚本名为svr4-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

$

shift $(($OPTIND - 1))是一个简单的脚本,它在一个星体框中回荡其参数:
echo "** $@ **" | sed -e h -e 's/./*/g' -e p -e x -e p -e x

我从1998年开始就没有修改过它;我不经常有一个子目录getopts里面有一个子目录包含一个文件gomod.sh,所以boxecho周围没有引号并没有咬到我,但是我已经修复了上面的脚本(在我的s目录中)。还有其他写g的方法;不过,这确实有效。
值得注意的是,s/./*/g函数中使用的bin与最初传递给该命令的全套参数一起工作,尽管这意味着它正在处理“剩余的参数”。如果函数要处理尚未处理的参数,则需要将sed传递给它。它也会立即遇到“结束参数”,除非您在环境中没有posixly_correct set的gnugetopts功能,因为第一个这样的参数将是parseRemainingArgs,这不是一个选项,并且将终止"$@"处理。

关于linux - bash中多次调用getopts,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/33515668/

10-13 07:23