3. Shell的基本語法

3.1. 變數

按照慣例,Shell變數由全大寫字母加下劃線組成,有兩種類型的Shell變數:

環境變數

第 2 節 “環境變數”中講過,環境變數可以從父進程傳給子進程,因此Shell進程的環境變數可以從當前Shell進程傳給fork出來的子進程。用printenv命令可以顯示當前Shell進程的環境變數。

本地變數

只存在於當前Shell進程,用set命令可以顯示當前Shell進程中定義的所有變數(包括本地變數和環境變數)和函數。

環境變數是任何進程都有的概念,而本地變數是Shell特有的概念。在Shell中,環境變數和本地變數的定義和用法相似。在Shell中定義或賦值一個變數:

$ VARNAME=value

注意等號兩邊都不能有空格,否則會被Shell解釋成命令和命令行參數。

一個變數定義後僅存在於當前Shell進程,它是本地變數,用export命令可以把本地變數導出為環境變數,定義和導出環境變數通常可以一步完成:

$ export VARNAME=value

也可以分兩步完成:

$ VARNAME=value
$ export VARNAME

unset命令可以刪除已定義的環境變數或本地變數。

$ unset VARNAME

如果一個變數叫做VARNAME,用${VARNAME}可以表示它的值,在不引起歧義的情況下也可以用$VARNAME表示它的值。通過以下例子比較這兩種表示法的不同:

$ echo $SHELL
$ echo $SHELLabc
$ echo $SHELL abc
$ echo ${SHELL}abc

注意,在定義變數時不用$,取變數值時要用$。和C語言不同的是,Shell變數不需要明確定義類型,事實上Shell變數的值都是字元串,比如我們定義VAR=45,其實VAR的值是字元串45而非整數。Shell變數不需要先定義後使用,如果對一個沒有定義的變數取值,則值為空字元串。

3.2. 檔案名代換(Globbing):* ? []

這些用於匹配的字元稱為通配符(Wildcard),具體如下:

表 31.1. 通配符

*匹配0個或多個任意字元
?匹配一個任意字元
[若干字元]匹配方括號中任意一個字元的一次出現

$ ls /dev/ttyS*
$ ls ch0?.doc
$ ls ch0[0-2].doc
$ ls ch[012][0-9].doc

注意,Globbing所匹配的檔案名是由Shell展開的,也就是說在參數還沒傳給程序之前已經展開了,比如上述ls ch0[012].doc命令,如果當前目錄下有ch00.docch02.doc,則傳給ls命令的參數實際上是這兩個檔案名,而不是一個匹配字元串。

3.3. 命令代換:`或 $()

由反引號括起來的也是一條命令,Shell先執行該命令,然後將輸出結果立刻代換到當前命令行中。例如定義一個變數存放date命令的輸出:

$ DATE=`date`
$ echo $DATE

命令代換也可以用$()表示:

$ DATE=$(date)

3.4. 算術代換:$(())

用於算術計算,$(())中的Shell變數取值將轉換成整數,例如:

$ VAR=45
$ echo $(($VAR+3))

$(())中只能用+-*/和()運算符,並且只能做整數運算。

3.5. 轉義字元\

和C語言類似,\在Shell中被用作轉義字元,用於去除緊跟其後的單個字元的特殊意義(回車除外),換句話說,緊跟其後的字元取字面值。例如:

$ echo $SHELL
/bin/bash
$ echo \$SHELL
$SHELL
$ echo \\
\

比如創建一個檔案名為“$ $”的檔案可以這樣:

$ touch \$\ \$

還有一個字元雖然不具有特殊含義,但是要用它做檔案名也很麻煩,就是-號。如果要創建一個檔案名以-號開頭的檔案,這樣是不行的:

$ touch -hello
touch: invalid option -- h
Try `touch --help' for more information.

即使加上\轉義也還是報錯:

$ touch \-hello
touch: invalid option -- h
Try `touch --help' for more information.

因為各種UNIX命令都把-號開頭的命令行參數當作命令的選項,而不會當作檔案名。如果非要處理以-號開頭的檔案名,可以有兩種辦法:

$ touch ./-hello

或者

$ touch -- -hello

\還有一種用法,在\後敲回車表示續行,Shell並不會立刻執行命令,而是把光標移到下一行,給出一個續行提示符>,等待用戶繼續輸入,最後把所有的續行接到一起當作一個命令執行。例如:

$ ls \
> -l
(ls -l命令的輸出)

3.6. 單引號

和C語言不一樣,Shell腳本中的單引號和雙引號一樣都是字元串的界定符(雙引號下一節介紹),而不是字元的界定符。單引號用於保持引號內所有字元的字面值,即使引號內的\和回車也不例外,但是字元串中不能出現單引號。如果引號沒有配對就輸入回車,Shell會給出續行提示符,要求用戶把引號配上對。例如:

$ echo '$SHELL'
$SHELL
$ echo 'ABC\(回車)
> DE'(再按一次回車結束命令)
ABC\
DE

3.7. 雙引號

雙引號用於保持引號內所有字元的字面值(回車也不例外),但以下情況除外:

  • $加變數名可以取變數的值

  • 反引號仍表示命令替換

  • \$表示$的字面值

  • \`表示`的字面值

  • \"表示"的字面值

  • \\表示\的字面值

  • 除以上情況之外,在其它字元前面的\無特殊含義,只表示字面值

$ echo "$SHELL"
/bin/bash
$ echo "`date`"
Sun Apr 20 11:22:06 CEST 2003
$ echo "I'd say: \"Go for it\""
I'd say: "Go for it"
$ echo "\"(回車)
>"(再按一次回車結束命令)
"

$ echo "\\"
\