簡體   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