繁体   English   中英

bash中多次调用getopts

[英]Multiple calls to getopts in bash

调用此脚本时

test.sh -a 1 -b 2 -c 3

输出为: -a 1 -b 2 1

我期待parseRemainingArgs解析并打印所有参数。 如您所见,所有参数都正确地传递到parseRemainingArgs如输出的第一行所示,但它仅解析第一个参数。

我也设置了OPTIND,但这也无济于事。

在确定问题出在哪里以及如何解决该问题方面需要帮助。

尝试了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 观察到

为了解决这个问题,可以请您使用以下参数测试脚本

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

在这种情况下, -t将在parseArgs匹配,但是parseRemainingArgs将无法解析其余的args。 当未给出parseArgs中匹配的-t-h时,它的效果很好。

好; 这就是我使用的脚本所期望的(请参见下面的“'无法重现'响应”部分中的脚本,这是对问题内容的温和扩展)。 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
$

这是因为您在parseArgs的开始处设置了AllArgs的结果。 当您在parseArgs解析"$@"中的参数时,它不会改变,因此您将原始参数列表传递给parseRemainingArgs ,如诊断输出所示。 parseRemainingArgs-t不是选项,因此循环会在-t上返回错误(因此Ignoring error ),然后退出,因为a不是选项。

您可以从以下获得更多输出:

$ 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
$

它忽略parseRemainingArgs-t错误,然后使用相应的参数处理-a-b-c-a

或者,您可以修改脚本,将parseRemainingArgs的调用替换为:

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
$

请注意,一无所获或用abelone (或其他任何非选项)代替--都无法正常工作。

您仍然可以添加更多调试信息,以使其更易于理解,或者在bash -x下运行它。

“无法复制”响应

我不确定您的问题了。 我已经运行了稍微修改过的脚本版本-进行了更多诊断,并使用了反引号和expr来计算偏移量(因为我测试过的某些shell不支持$((…))算术符号)。 代码是:

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

测试的外壳是:

  • shbash的链接
  • bash
  • dash
  • ksh — Korn外壳
  • zsh
  • hsh —传家宝外壳(接近伯恩外壳)
  • svr4-sh — Unix System V发行版4(稍微加重了Bourne shell)

其中, hshsvr4-sh不接受shift $(($OPTIND - 1)) 我很惊讶Heirloom shell完全识别出getopts

该脚本称为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是一个简单的脚本,它在一个星星盒内回显其参数:

echo "** $@ **" | sed -e h -e 's/./*/g' -e p -e x -e p -e x

自1998年以来,我从未进行过修改。 我通常不会在子目录s有一个包含文件g的子目录,因此在s/./*/g周围没有引号并没有引起我的注意,但是我已经修复了上面的脚本(和在我的bin目录中)。 编写sed也有其他方法。 但这确实有效。

值得注意的是,尽管暗示它正在处理“其余参数”,但在parseRemainingArgs函数中使用getopts可以与最初传递给命令的全套参数一起使用。 如果要处理尚未处理的参数,则将"$@"传递给该函数。 除非您在环境中未设置POSIXLY_CORRECT的情况下具有GNU getopts功能,否则它也会立即遇到“参数结尾”,因为第一个此类参数为1这不是选项),将终止getopts处理。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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