2008/10/02

Bash 參數的展開

bash parameter expansion一文對 bash 在變數(參數)的解釋有不錯的說明。

寫 shell script 不難,變數(參數)的取用也相對容易,最簡單的是像 $a 這種型式,指定值的時候是 a=變數值, 早期等號(=)前後不能有空白,但是這邊提醒一下,養成良好的習慣遠比什麼效率或美感重要,通常我在引用變數時都寫成 ${a} 的方式。其中的原因在於不讓 shell 解釋錯誤,例如 ${a}bc。而像字串的比對,我也會加上引號,例如 [ "${a}" = "" ],因為你雖然可以很確定卻永遠不會知道 ${a} 是否真的正確定義。

因為上面的說明裡面講到「正確定義」這件事,所以 bash 有「預設值」的用法,b=${b:-預設值},例如 LENGTH=${LEN:-0} 就會在 LEN 沒被定義時指定 0 給 LENGTH

這邊有個 test.sh 裡面是這樣寫的:

TEST_MODE=${TEST_MODE:-0}
...
if [[ $TEST_MODE -eq 0 ]]; then
echo "Running in live mode"
else
echo "Running in test mode"
fi

除了使用了預設值的觀念外,平常 shell script 在執行時 TEST_MODE 的值是 0, 若你想機動的將之變成 test mode 相對上非常簡單,語法如下:

$ env TEST_MODE=1 sh test.sh

變數在使用時,有些「編輯」動作可以用,先講一個不常見的搜尋與取代用法 ${VAR/search/replace}

VAR=aabbcc
echo ${VAR/b/-dd-}

結果會是 aa-dd-bcc <-- 只取代了一個,要想全部取代請用 ${VAR//search/replace}:

VAR=aabbcc
echo ${VAR//b/-dd-}

結果就會是 aa-dd--dd-cc。值得注意的是,別把 perl 常用的語法應用在這兒,取代的後面沒有斜線,我就不多寫省得學錯。

另外最出名的,就是 %, %%, #, ## 這種的編輯方式,直接舉例來看:

file=/home/wade/data.txt
echo "${file%/*}" # /home/wade
echo "${file##*/}" # data.txt

結果寫在註解中, # 與 % 的差別在於前置與後置,可以藉由在鍵盤上的排列來聯想,兩個都有著「餘」數的概念,其中 % 是將字串扣掉後面符合比對字串「最短」內容,因為比對字串是 /* 因此有三個 / 符合,扣掉最短的內容 /data.txt 後就剩下 /home/wade。而 ## 則是將字串扣掉前面符合比對字串「最長」內容。多用就會有感覺。

也可以取得變數特定位置的子字串,有點像 substr(),語法為 ${VAR:offset:length}, 其中 offset 若被省略表示從頭開始,而 length 省略表示一直到字串的最後,例如:

$ VAR=/home/wade/data.txt

$ echo ${VAR:10}
/data.txt

$ echo ${VAR::10}
/home/wade

有一點值得注意的是,若 offset 是負數則表示從後面數過來,可是負數前面加上冒號 ':' 又會被解釋成預設值,因此得用 shell 的數學運算符號 $(( ... )),例如 $ echo ${VAR:$((-4)):1} 會輸出 '.' 這個字元,當然若能夠將數字的引用以變數取代就不會有此困擾,例如:
echo $OFFSET=-4
echo ${VAR:$OFFSET:1}


其它還可以傳回變數字串的長度,例如 echo ${#VAR} 的值是 19

有些內建變數也應該知道,例如 $$, $0, $1, $?, 其意義分別是: PID, 命令本身,第一個參數,以及前一命令的傳回值

0 意見: