[英]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 $@
為了解決這個問題,可以請您使用以下參數測試腳本
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 "$@"
測試的外殼是:
sh
— bash
的鏈接 bash
dash
ksh
— Korn外殼 zsh
hsh
—傳家寶外殼(接近伯恩外殼) svr4-sh
— Unix System V發行版4(稍微加重了Bourne shell) 其中, hsh
和svr4-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.