getopts 問題請教 [論壇 - Ubuntu 程式設計]


正在瀏覽:   1 名遊客


 到底部   前一個主題   下一個主題  [無發表權] 請登錄或者註冊



getopts 問題請教
會員二級
註冊日期:
2015/11/16 9:07
所屬群組:
已註冊使用者
等級: 6
HP : 0 / 137
MP : 19 / 3155
EXP: 48
離線
您好:
我 使用getopts 來抓參數,但最後-各 -h 卻沒抓到
請問 這是哪一段出問題?
謝謝!

$ . 94.sh -f abc -g xxx -h 444 999
argument of -f is abc
argument of -g is 000
argument of -h is
other args: 444 999



************************
while getopts "f:g:h:" flag; do
case $flag in
f) opt_f="$OPTARG";;
g) opt_g="$OPTARG";;
h) opt_h="$OPTARG";;
*) opt_o="NO";;
esac
done

echo "argumnt of -f is ${opt_f}"
echo "argumnt of -g is ${opt_g}"
echo "argumnt of -h is ${opt_h}"

shift $((OPTIND-1))
echo "OTHER args: $*"

2016/4/1 11:19
應用擴展 工具箱
回覆: getopts 問題請教
會員五級
註冊日期:
2012/4/22 10:50
所屬群組:
已註冊使用者
等級: 37
HP : 0 / 905
MP : 679 / 30289
EXP: 23
離線
wayout 寫到:
您好:
我 使用getopts 來抓參數,但最後-各 -h 卻沒抓到
請問 這是哪一段出問題?
謝謝!

$ . 94.sh -f abc -g xxx -h 444 999
argument of -f is abc
argument of -g is 000
argument of -h is
other args: 444 999



************************
while getopts "f:g:h:" flag; do
case $flag in
f) opt_f="$OPTARG";;
g) opt_g="$OPTARG";;
h) opt_h="$OPTARG";;
*) opt_o="NO";;
esac
done

echo "argumnt of -f is ${opt_f}"
echo "argumnt of -g is ${opt_g}"
echo "argumnt of -h is ${opt_h}"

shift $((OPTIND-1))
echo "OTHER args: $*"





您貼出來的程式碼,跟測試的結果,好像沒有match?

我這邊測試的結果如下

## 範例一

「test_1.sh」


#!/usr/bin/env bash

while getopts "f:g:h:" flag; do
case $flag in
f) opt_f="$OPTARG";;
g) opt_g="$OPTARG";;
h) opt_h="$OPTARG";;
*) opt_o="NO";;
esac
done

echo "argumnt of -f is ${opt_f}"
echo "argumnt of -g is ${opt_g}"
echo "argumnt of -h is ${opt_h}"

shift $((OPTIND-1))
echo "OTHER args: $*"



執行


$ ./test_1.sh -f abc -g xxx -h 444 999



顯示


argumnt of -f is abc
argumnt of -g is xxx
argumnt of -h is 444
OTHER args: 999





## 範例二

「test_2.sh」


#!/usr/bin/env bash

while getopts "f:g:h" flag; do
case $flag in
f) opt_f="$OPTARG";;
g) opt_g="$OPTARG";;
h) opt_h="$OPTARG";;
*) opt_o="NO";;
esac
done

echo "argumnt of -f is ${opt_f}"
echo "argumnt of -g is ${opt_g}"
echo "argumnt of -h is ${opt_h}"

shift $((OPTIND-1))
echo "OTHER args: $*"



執行


$ ./test_2.sh -f abc -g xxx -h 444 999



顯示


argumnt of -f is abc
argumnt of -g is xxx
argumnt of -h is
OTHER args: 444 999




兩個範例,只有差在「"f:g:h:"」和「"f:g:h"」

最後的「h」,一個有「:」,一個沒有「:」。

看說明


$ help getopts




getopts: getopts optstring name [arg]
Parse option arguments.

Getopts is used by shell procedures to parse positional parameters
as options.

OPTSTRING contains the option letters to be recognized; if a letter
is followed by a colon, the option is expected to have an argument,
which should be separated from it by white space.

...略...




注意下面這一段


if a letter is followed by a colon, the option is expected to have an argument,
which should be separated from it by white space.


「colon」指的是「:」

意思就是

OPTSTRING的「h」後面若有接「:」,也就是「h:」,
則表示,「-h」後面空白隔開的,就是參數值,
以上面的例子來說,也就是「-h 444 999」,「h」會被放到「name」, 「444」會被放到「OPTARG」,「999」跟這個「h」無關。

OPTSTRING的「h」後面若沒有接「:」,也就是「h」,
以上面的例子來說,也就是「-h 444 999」,「h」會被放到「name」, 「OPTARG」則是沒有值。「444 999」跟這個「h」無關。

2016/4/1 13:12
應用擴展 工具箱
回覆: getopts 問題請教
會員二級
註冊日期:
2015/11/16 9:07
所屬群組:
已註冊使用者
等級: 6
HP : 0 / 137
MP : 19 / 3155
EXP: 48
離線
您好:
謝謝!
我在測試過
1.我援用的測試環境為cygwin,所以用您的範例,也會 最後一個
h) opt_h="$OPTARG";;

抓不到資料的問題!

2.另外想請教
以下範例中
set - `getopt ab:c: $*`
「 $*」 的用意為何?

整段是要湊出 set -a -b xx -c xx的 情境嗎?

另外
*)
echo "error!"
return 1
;;
這一段,要如何才會 跑到這一段?
謝謝!


---------------------------------------------
set - `getopt ab:c: $*`
while true
do
case $1 in
-a) echo option -a
echo $1 $2
shift
;;
-b) echo option -b=$2
shift 2
;;
-c) echo option -c=$2
shift 2
;;
--)
echo "--xx"
shift
break
;;
*)
echo "error!"
return 1
;;
esac
done

2016/4/1 14:30
應用擴展 工具箱
回覆: getopts 問題請教
會員五級
註冊日期:
2012/4/22 10:50
所屬群組:
已註冊使用者
等級: 37
HP : 0 / 905
MP : 679 / 30289
EXP: 23
離線
wayout 寫到:
您好:
謝謝!
我在測試過
1.我援用的測試環境為cygwin,所以用您的範例,也會 最後一個
h) opt_h="$OPTARG";;

抓不到資料的問題!



喔喔!若是cygwin,這樣我就愛莫能助了,我沒有這樣的環境。

我的環境是
「Xubuntu 14.04 64位元」
「GNU bash, version 4.3.11(1)-release (x86_64-pc-linux-gnu)」。

以下開始說明,回覆其他的提問,有點長,Orz...

================================================================================


「 $* 」和「$@」,一般的狀況下,意思是一樣的,請看下面的範例

## 範例一

「test_1.sh」


#!/usr/bin/env bash

echo $*



執行


$ ./test_1.sh a b c



顯示


a b c




## 範例二

「test_2.sh」


#!/usr/bin/env bash

echo $@



執行


$ ./test_2.sh a b c



顯示


a b c




更多說明請看「$ man bash」。

可以看到下面這一段


Special Parameters
The shell treats several parameters specially. These parameters may only be referenced; assignment to them is
not allowed.
* Expands to the positional parameters, starting from one. When the expansion is not within double
quotes, each positional parameter expands to a separate word. In contexts where it is performed, those
words are subject to further word splitting and pathname expansion. When the expansion occurs within
double quotes, it expands to a single word with the value of each parameter separated by the first char‐
acter of the IFS special variable. That is, "$*" is equivalent to "$1c$2c...", where c is the first
character of the value of the IFS variable. If IFS is unset, the parameters are separated by spaces.
If IFS is null, the parameters are joined without intervening separators.
@ Expands to the positional parameters, starting from one. When the expansion occurs within double
quotes, each parameter expands to a separate word. That is, "$@" is equivalent to "$1" "$2" ... If the
double-quoted expansion occurs within a word, the expansion of the first parameter is joined with the
beginning part of the original word, and the expansion of the last parameter is joined with the last
part of the original word. When there are no positional parameters, "$@" and $@ expand to nothing
(i.e., they are removed).




================================================================================

「getopt」 和 「getopts」是不一樣的指令

執行


$ type getopt



顯示


getopt is hashed (/usr/bin/getopt)




執行


$ type getopts



顯示


getopts is a shell builtin




* man getopt

* man getopts
* help getopts


================================================================================

執行


$ getopt ab:c:



顯示


--



執行


$ getopt ab:c w x y z



顯示


-- w x y z



執行


$ getopt ab:c: -ab w -c x y z



顯示


-a -b w -c x -- y z




執行


$ getopt ab:c: -a -b w -c x y z



跟上面一的例子一樣顯示


-a -b w -c x -- y z



================================================================================


## 範例三

「test_3.sh」


#!/usr/bin/env bash

getopt ab:c: $*



執行


$ ./test_3.sh -ab w -c x y z



顯示


-a -b w -c x -- y z




執行


$ ./test_3.sh -a -b w -c x y z



顯示


-a -b w -c x -- y z




這個例子,是綜合上面所講的

一開頭講的「$*」指的是「-a -b w -c x y z」,

所以「getopt ab:c: $*」會被展開變成「getopt ab:c: -a -b w -c x y z」


================================================================================


範例四


#!/usr/bin/env bash

echo `getopt ab:c: $*`




執行


$ ./test_4.sh -ab w -c x y z



顯示


-a -b w -c x -- y z




執行


$ ./test_4.sh -a -b w -c x y z



顯示


-a -b w -c x -- y z




「``」的用法,之前「討論」有討論過,再次複習

更多請參考「man bash」,找尋「Command Substitution」



...略...

Command Substitution
Command substitution allows the output of a command to replace the
command name. There are two forms:

$(command)
or
`command`

...略...




================================================================================

再來


set - `getopt ab:c: $*`



請看「set」的說明,


$ help set



找尋參數「-」,可以看到下面這段說明



Options:
...略...

- Assign any remaining arguments to the positional parameters.
The -x and -v options are turned off.




以剛剛的範例,「set - `getopt ab:c: $*`」就會展開成「set - -a -b w -c x -- y z」。


## 範例五

「test_5.sh」


#!/usr/bin/env bash

set - -a -b w -c x -- y z
echo $@




執行


$ ./test_5.sh



顯示


-a -b w -c x -- y z



這樣應該可以解惑你問的這段


wayout 寫到:

2.另外想請教
以下範例中
set - `getopt ab:c: $*`
「 $*」 的用意為何?

整段是要湊出 set -a -b xx -c xx的 情境嗎?



================================================================================

再來討論你給的範例

wayout 寫到:
#!/usr/bin/env bash

set - `getopt ab:c: $*`
while true
do
case $1 in
-a) echo option -a
echo $1 $2
shift
;;
-b) echo option -b=$2
shift 2
;;
-c) echo option -c=$2
shift 2
;;
--)
echo "--xx"
shift
break
;;
*)
echo "error!"
return 1
;;
esac
done





範例六

「test_6.sh」


#!/usr/bin/env bash

set - -a -b w -c x -- y z

echo '$@:' $@
echo '$*:' $*

echo '$1:' $1
echo '$2:' $2
echo '$3:' $3
echo '$4:' $4
echo '$5:' $5
echo '$6:' $6
echo '$7:' $7
echo '$8:' $8



執行


$ ./test_6.sh




顯示


$@: -a -b w -c x -- y z
$*: -a -b w -c x -- y z
$1: -a
$2: -b
$3: w
$4: -c
$5: x
$6: --
$7: y
$8: z



================================================================================

## 範例 七

「test_7.sh」


#!/usr/bin/env bash

set - -a -b w -c x -- y z

echo '$@:' $@
echo '$*:' $*

echo '================================='

# -a

echo 'opt:' $1
shift

echo '================================='

# -b w

echo 'opt:' $1
echo 'val:' $2
shift 2

echo '================================='

# -c x

echo 'opt:' $1
echo 'val:' $2
shift 2

echo '================================='

# --

echo 'flag:' $1
shift 1

echo '================================='

# y

echo 'arg:' $1
shift 1

echo '================================='

# z

echo 'arg:' $1
shift 1

echo '================================='



執行


$ ./test_7.sh



顯示


$@: -a -b w -c x -- y z
$*: -a -b w -c x -- y z
=================================
opt: -a
=================================
opt: -b
val: w
=================================
opt: -c
val: x
=================================
flag: --
=================================
arg: y
=================================
arg: z
=================================




這個範例,就是模擬您給的範例,您給的範例,只是跑一個無窮迴圈,
然後比對每一個「positional parameter」,然後做處理,
透過「shift」,才可以一直使用「case $1 in」來做每一個「positional parameter」的比對,效果就好像一個指標不斷的移動位置。


## 範例八

「test_8.sh」


#!/usr/bin/env bash

set - -a -b w -c x -- y z

echo '$@:' $@
echo '$*:' $*

echo '================================='

while true; do
case $1 in
--)
echo "==end=="
#shift
break
;;
*)
echo $1
shift
;;
esac
done




執行


$ ./test_8.sh



顯示



$@: -a -b w -c x -- y z
$*: -a -b w -c x -- y z
=================================
-a
-b
w
-c
x
==end==




================================================================================

我目前還研究不出來,怎樣引發跑到「echo "error!"」那一段,
看起來 `getopt ab:c: $*` 就會限定一些內容
然後到「--)」那一段,就已經「break」,跳出無窮迴圈了。
看看有沒有其他人可以解釋,
也或許那只是寫著預防未知的例外狀況發生,Orz...

wayout 寫到:

另外
*)
echo "error!"
return 1
;;
這一段,要如何才會 跑到這一段?
謝謝!

---------------------------------------------
set - `getopt ab:c: $*`
while true
do
case $1 in
-a) echo option -a
echo $1 $2
shift
;;
-b) echo option -b=$2
shift 2
;;
-c) echo option -c=$2
shift 2
;;
--)
echo "--xx"
shift
break
;;
*)
echo "error!"
return 1
;;
esac
done



================================================================================

2016/4/1 18:10
應用擴展 工具箱
回覆: getopts 問題請教
會員二級
註冊日期:
2015/11/16 9:07
所屬群組:
已註冊使用者
等級: 6
HP : 0 / 137
MP : 19 / 3155
EXP: 48
離線
謝謝您,
現在知道cygwin的問題就OK了!
另外您在回覆的文章,我在消化一下,謝謝!

2016/4/2 15:16
應用擴展 工具箱
回覆: getopts 問題請教
會員二級
註冊日期:
2015/11/16 9:07
所屬群組:
已註冊使用者
等級: 6
HP : 0 / 137
MP : 19 / 3155
EXP: 48
離線
您好:
想再確認一下set - 與 Set -- 的差異?
只是「--」後面沒接 參數,就表示清除嗎?
還是 這2個用法有其他差異?

謝謝!

「--」
If no arguments follow this option, then the positional parameters are unset. Otherwise, the positional parameters are set to the arguments, even if some of them begin with a ‘-’.
「-」
Signal the end of options, cause all remaining arguments to be assigned to the positional parameters. The -x and -v options are turned off. If there are no arguments, the positional parameters remain unchanged.

2016/4/7 14:07
應用擴展 工具箱
回覆: getopts 問題請教
會員五級
註冊日期:
2012/4/22 10:50
所屬群組:
已註冊使用者
等級: 37
HP : 0 / 905
MP : 679 / 30289
EXP: 23
離線
wayout 寫到:
您好:
想再確認一下set - 與 Set -- 的差異?
只是「--」後面沒接 參數,就表示清除嗎?
還是 這2個用法有其他差異?

謝謝!

「--」
If no arguments follow this option, then the positional parameters are unset. Otherwise, the positional parameters are set to the arguments, even if some of them begin with a ‘-’.
「-」
Signal the end of options, cause all remaining arguments to be assigned to the positional parameters. The -x and -v options are turned off. If there are no arguments, the positional parameters remain unchanged.



我目前解讀和測試的也是如此,
再看看有沒有其他人知道是否還有差異的用法,可以提供,感恩先

以下測試範例

1.sh


#!/usr/bin/env bash

set -

echo $*



執行


$ ./1.sh a b c



顯示


a b c



==========================================

2.sh


#!/usr/bin/env bash

set --

echo $*



執行


$ ./2.sh a b c



顯示空白行





2016/4/7 14:20
應用擴展 工具箱


 [無發表權] 請登錄或者註冊


可以查看帖子.
不可發帖.
不可回覆.
不可編輯自己的帖子.
不可刪除自己的帖子.
不可發起投票調查.
不可在投票調查中投票.
不可上傳附件.
不可不經審核直接發帖.