SHELL十三問之九:$@ 與 $* 差在哪?

要說$@$*之前,需得先從shell scriptpositional parameter談起...我們都已經知道變量(variable)是如何定義及替換的,這個不用再多講了。但是,我們還需要知道有些變量是shell內定的,且其名稱是我們不能隨意修改的,其中就有positional parameter在內。BSD愛好者樂園(v5C f mS;bPGF

KBH qV-L4fg
shell script中,我們可用$0, $1, $2, $3 ...這樣的變量分別提取命令行中的如下部份:BSD愛好者樂園:{5o|~)kZ2e

script_name parameter1 parameter2 parameter3 ...

C4m9eH {HC

我們很容易就能猜出$0就是代表shell script名稱(路徑)本身,而$1就是其後的第一個參數,如此類推....BSD愛好者樂園5yoG,~{-G4H
須得留意的是IFS的作用,也就是,若IFSquoting處理後,那麼positional parameter也會改變。

#of/q IJ ZxA
如下例:

S}1RS1srG3Y

my.sh p1 "p2 p3" p4

%F I:x,p(Z

由於在p2p3之間的空格鍵被soft quote所關閉了,因此my.sh中的$2"p2 p3"$3則是p4 ...BSD愛好者樂園r3TW�N�m/sJ,c%`
BSD愛好者樂園?#?OQ,~#Sm#m#i
還記得前兩章我們提到fucntion時,我不是說過它是script中的script嗎?
  ^_^
/r'j+yV(G�Kj,Ue*V,Li
是的,function一樣可以讀取自己的(有別於script) postitional parameter,惟一例外的是$0而已。
BSD愛好者樂園$dhD il
舉例而言:假設my.sh裏有一個fucntionmy_fun ,若在script中跑my_fun fp1 fp2 fp3,那麼,function內的$0my.sh,而$1則是fp1而非p1...
V /Ch;QBSD愛好者樂園VEI5}A
不如寫個簡單的my.sh script  看看吧:
BSD愛好者樂園-}6ISa8m�j-X

#!/bin/bashBSD愛好者樂園%x t AJ9W
BSD愛好者樂園{&]Ws nBS'h�e;K%V
my_fun() {
6]#H*G1G&@a.y$q5ig    echo '$0 inside function is '$0
q8rP;v.O    echo '$1 inside function is '$1
,c]M {-A3/ P5t1D&us    echo '$2 inside function is '$2
3R%FXW q(GGr}BSD愛好者樂園J ^n.P!^7SW;K

+Z(jr!lkAecho '$0 outside function is '$0
}*O)n.z"q)f*J/wecho '$1 outside function is '$1BSD愛好者樂園Wk#f2jMZ*m2t'U
echo '$2 outside function is '$2BSD愛好者樂園8/2_zi+gG ]

:l'~ Ja&pmy_fun fp1 "fp2 fp3"

{"JP.k[w0OF0f

然後在command line中跑一下script就知道了:BSD愛好者樂園#q{2c�T'^ v4R5GP2oa

chmod +x my.shBSD愛好者樂園 f;F'I$^w
./my.sh p1 "p2 p3"
6WL_7}u7w)Ji$0 outside function is ./my.shBSD愛好者樂園9N D{)D'e9f"P
$1 outside function is p1BSD愛好者樂園!IY#j(DZQY/qZ+v
$2 outside function is p2 p3BSD愛好者樂園OL[}dr,P4W5X&j-[2P
$0 inside function is ./my.shBSD愛好者樂園3J o8g*~ S7^)x |
$1 inside function is fp1
)xlVstz$2 inside function is fp2 fp3

8xy(Jbh6E2LRjQ

然而,在使用positional parameter的時候,我們要注意一些陷阱哦:BSD愛好者樂園7e Bt`0r;n p
* $10不是替換第10個參數,而是替換第一個參數($1)然後再補一個0於其後!
$q4dU^e pTR3~_
也就是,my.sh one two three four five six seven eigth nine ten這樣的command linemy.sh裏的$10不是ten而是one0...小心小心!BSD愛好者樂園i0SJ:`6A~
要抓到ten的話,有兩種方法:
U rIT0o5{BSD愛好者樂園*IE/s g s+d
方法一是使用我們上一章介紹的${ },也就是用${10}即可。
n p!RHjRBSD愛好者樂園e#Mb+W%n&}A
方法二,就是shift了。
"aZKyt-v4L_
用通俗的說法來說,所謂的shift就是取消positional parameter中最左邊的參數( $0不受影響)。其默認值爲1,也就是shiftshift 1  都是取消$1,而原本的$2則變成$1$3變成$2 ...shift 3則是取消前面三個參數,也就是原本的$4將變成$1 ...
E;R.b#R&{2s7P-v
那,親愛的讀者,你說要shift掉多少個參數,纔可用$1取得${10}呢?
^_^BSD愛好者樂園{/L `%{d%_+uLvj�^
BSD愛好者樂園-G/w8T0K$^4^2}{
okay
,當我們對positional parameter有了基本概念之後,那再讓我們看看其它相關變量吧。

0H)w'B(AT#/:iS
首先是$#:它可抓出positional parameter的數量。
/[Nct1x4pl-S]Z w
以前面的my.sh p1 "p2 p3"爲例:BSD愛好者樂園/C5eKC5FH O9ni
由於p2p3之間的IFS是在soft quote中,因此$#可得到2的值。BSD愛好者樂園8M"p L'a�V/a
但如果p2p3沒有置於quoting中話,那$#就可得到3的值了。BSD愛好者樂園xC%[1u'x:A|$x
同樣的道理在function中也是一樣的...BSD愛好者樂園*{_mn)] NV3C`
BSD愛好者樂園/%q1|�v$L~(X?
因此,我們常在shell script裏用如下方法測試script是否有讀進參數:

-V~#| DtbE+s

 [ $# = 0 ]BSD愛好者樂園G Vs7J ~

假如爲0,那就表示script沒有參數,否則就是有帶參數...BSD愛好者樂園p,_�xf t_0Rd

3RQ8p}�tT'U7i$h:q
接下來就是$@$*
BSD愛好者樂園 c+A)H*}#j7?
精確來講,兩者只有在soft quote中才有差異,否則,都表示"全部參數"( $0除外)
N'[@'Xwz8B ?b*Bi
舉例來說好了:BSD愛好者樂園A zWl3K
若在command line上跑my.sh p1 "p2 p3" p4的話,
O6P#?'Rf(Y8I
不管是$@還是$*,都可得到p1 p2 p3 p4就是了。
bf(~'V({z
但是,如果置於soft quote中的話:
w,T~X t/Il"$@"
則可得到"p1" "p2 p3" "p4"這三個不同的詞段(word)
n7sj/%q~4yO"$*"
則可得到"p1 p2 p3 p4"這一整串單一的詞段。
yG7X@H9M
}cr0f D0Grf
我們可修改一下前面的my.sh,使之內容如下:

]|&]3NCD;j{ P {

#!/bin/bash
5qBTB)[{B {kBSD愛好者樂園8nL7e^)`BqVt
my_fun() {BSD愛好者樂園6of)KDz?,R
    echo "$#"
9@v;GM6Zxz+/M0?}
S T^K-}/)v
'Bg!L"Ol+]1|,gecho 'the number of parameter in "$@" is '$(my_fun "$@")
JB*TXow.F3Wecho 'the number of parameter in "$*" is '$(my_fun "$*")

y.dz%K_Hv3z3?

然後再執行./my.sh p1 "p2 p3" p4就知道$@$*差在哪了... 

}b;SGMI.m

the number of parameter in "$@" is3BSD愛好者樂園2x$CK#A0L%D

the number of parameter in "$*" is1

發佈了42 篇原創文章 · 獲贊 5 · 訪問量 19萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章