##shell十三問之9:$@與$*差在哪?
------
要說$@與$*之前,
需得先從shell script的positional parameter談起...
我們都已經知道變量(variable)是如何定義和替換的,
這個不再多講了。
#### 1. shell script的positional parameter
--------------
但是,我們還需要知道有些變量是shell內定的,
且其名稱是我們不能隨意修改的。
其中,就有positional parameter在內。
在shell script中,我們可用$0, $1, $2, $3 ...
這樣的變量分別提取命令行中的如下部分:
```shell
script_name parameter1 parameter2 parameter3 ...
```
我們很容易就能猜出, `$0`就是代表 shell script名稱(路徑)本身,
而`$1`就是其后的第一個參數,如此類推...
須得留意的是`IFS`的作用, 也就是`IFS`被quoting處理后,
那么positional parameter也會改變。
如下例:
```shell
my.sh p1 "p2 p3" p4
```
由于p2與p3之間的空白鍵被soft quoting所關閉了,
因此,my.sh的中$2是"p2 p3",而$3則是p4...
還記得前兩章,我們提到function時,
我們不是說過,它是script中的script嗎?^_^
是的,function一樣可以讀取自己的(有別于script的)
positional parameter, 唯一例外的是$0而已。
舉例而言:
假設my.sh里有一個函數(function)叫my_fun,
若在script中跑`my_fun fp1 fp2 fp3`,
那么,function內的$0就是my.sh,而$1是fp1而不是p1了...
不如寫個簡單的my.sh script 看看吧:
```shell
#!/bin/bash
my_fun() {
echo '$0 inside function is '$0
echo '$1 inside function is '$1
echo '$2 inside function is '$2
}
echo '$0 outside function is '$0
echo '$1 outside function is '$1
echo '$2 outside function is '$2
my_fun fp1 "fp2 fp3"
```
然后在command line中跑一下 script就知道了:
```shell
chmod 755 my.sh
./my.sh p1 "p2 p3"
$0 outside function is ./my.sh
$1 outside function is p1
$2 outside function is p2 p3
$0 inside function is ./my.sh
$1 inside function is fp1
$2 inside function is fp2 fp3
```
然而,在使用positional parameter的時候,
我們要注意一些陷阱哦:
**$10不是替換第10個參數,
而是替換第一個參數,然后在補一個0于其后;**
也就是說, `my.sh one two three four five six seven eight nine ten`
這樣的command line, my.sh里的$10不是ten而是one0 哦...小心小心
要抓到ten的話,有兩種方法:
- 方法一:使用我們上一章介紹的${}, 也就是用${10}即可。
- 方法二:就是shift了。
用通俗的說法來說,
**所謂的shift就是取消positional parameter中最左邊的參數($0不受影響)**。
其預設值為1,也就是shift 或shift 1 都是取消$1,
而原本的$2則變成$1, $3則變成$2...
那親愛的讀者,你說要shift掉多少個參數,
才可用$1取得到${10} 呢? ^_^
okay,當我們對positional parameter有了基本的概念之后,
那再讓我們看看其他相關變量吧。
#### 2. shell script的positional parameter的number
--------------
先是$#, 它可抓出positional parameter的數量。
以前面的`my.sh p1 "p2 p3"`為例:
由于"p2 p3"之間的`IFS`是在soft quote中,
因此,$#就可得到的值是2.
但如果p2與p3沒有置于quoting中話,
那$#就可得到3的值了。
同樣的規則,在function中也是一樣。
因此,我們常在shell script里用如下方法,
測試script是否有讀進參數:
```shell
[ $# = 0 ]
```
假如為0, 那就表示script沒有參數,否則就是帶有參數...
#### 3. shell script中的$@與$*
-------------
接下來就是**$@與$*:
精確來講,兩者只有在soft quote中才有差異,
否則,都表示“全部參數” ($0除外)**。
若在comamnd line上, 跑`my.sh p1 "p2 p3" p4`的話,
不管$@還是$\*, 都可得到 p1 p2 p3 p4就是了。
但是,**如果置于soft quote中的話:**
- **"$@"則可得到 "p1" "p2 p3" "p4" 這三個不同字段(word);**
- **"$*"則可得到 "p1 p2 p3 p4" 這一整個單一的字段。**
我們修改一下前面的my.sh,使之內容如下:
```shell
#!/bin/bash
my_fun() {
echo "$#"
}
echo 'the number of parameter in "$@" is ' $(my_fun "$@")
echo 'the number of parameter in "$*" is ' $(my_fun "$*")
```
然后再執行:
```shell
./my.sh p1 "p2 p3" p4
```
就知道,$@與$*差在哪了... ^_^