介紹如何在 bash shell 指令稿中自行定義與使用函數(function)。
定義函數
在 bash shell 指令稿中可以像一般程式語言一樣自己定義函數,以下是一個簡單的範例:
# 定義函數
function hello () {
echo "Hello, world."
}
定義好函數之後,就可以像普通的指令一樣呼叫使用:
# 呼叫函數
hello
Hello, world.
上面那種定義函數的寫法是最完整的版本,我們也可以將 function 這個關鍵字省略:
# 定義函數(簡略寫法)
hello2 () {
echo "Hello, World."
}
或是將後方的一對小括號省略:
# 定義函數(簡略寫法)
function hello3 {
echo "Hello, World."
}
不管用哪一種寫法,對於程式來說效果都一樣,差異只在於程式碼是否清晰好讀。
傳入參數
呼叫 bash 函數的時候,也可以透過參數將資料傳遞至函數之中,函數的參數不需要事先定義,只要直接在函數之中以 $1、$2、$3… 等特殊變數取得傳入的參數即可,$1 代表第一個傳入的參數,$1 則代表第二個傳入的參數,以此類推:
# 在函數中取得傳入參數
function greeting () {
echo "Hello, $1."
}
# 呼叫函數並傳入參數
greeting "Joe"
Hello, Joe.
bash 函數可以動態接受任意數量的參數,傳入參數的數量可以從 $# 這個特殊變數取得,而所有的參數則可統一從 $* 或 $@ 兩個特殊變數中取得:
# 可接受任意數量參數的函數
function greeting2 () {
# 取得參數數量
echo "數量:$#"
# 逐一處理每一個參數
for name in $*
do
echo "Hello, $name."
done
}
# 傳入任意數量參數
greeting2 "Joe" "Mary" "Adora"
數量:3 Hello, Joe. Hello, Mary. Hello, Adora.
$* 與 $@ 的差別在於放在雙引號之中的時候,"$*" 會轉換為 "$1 $2 $3 ...",而 "$@" 會轉換為 "$1" "$2" "$3" ...,除此之外兩者沒有其他的差異。
函數傳回值
bash 的函數無法像普通的程式語言一樣可以傳回任意的值,當 bash 函數執行結束之後,只會傳回一個整數的傳回值,代表執行成功與否,0 代表成功,而 1 到 255 則代表各種錯誤。
若要指定函數的傳回數值,可以使用 return,然後搭配 $? 來取得函數的傳回值,而通常我們在取得函數的傳回值之後,會接著判斷函數是否有執行成功。
function myfunc () {
# 函數傳回值
return 35
}
# 呼叫函數
myfunc
# 取得傳回值
val=$?
# 根據傳回值判斷成功與否
if [ ! $val -eq 0 ]; then
echo "執行失敗,錯誤代碼:$val"
fi
執行失敗,錯誤代碼:35
全域變數傳遞資料
如果需要從函數中傳回整數以外的資料,最簡單的辦法就是透過全域變數傳遞:
function myfunc () {
# 將結果儲存至全域變數中
result="my result"
}
# 呼叫函數
myfunc
# 透過全域變數取得執行結果
echo $result
my result
透過標準輸出傳遞資料
除了使用全域變數傳回資料之外,也可以運用標準輸出來傳遞,這種作法比較複雜一些,但是可以避免使用全域變數:
function myfunc () {
# 將結果輸出至標準輸出
echo "my result"
}
# 呼叫函數,並從標準輸出取得傳回的資料
result=$(myfunc)
# 輸出結果
echo $result
my result
變數範圍
bash 函數內部所定義的變數預設都是全域變數,如果需要定義一個只有在函數內部使用的區域變數,可以使用 local 關鍵字:
# 全域變數
var1='A'
var2='B'
function myfunc () {
# 定義區域變數
local var1='C'
# 改變全域變數
var2='D'
echo "函數內部: var1=$var1, var2=$var2"
}
echo "函數執行前: var1=$var1, var2=$var2"
# 執行函數
myfunc
echo "函數執行後: var1=$var1, var2=$var2"
函數執行前: var1=A, var2=B 函數內部: var1=C, var2=D 函數執行後: var1=A, var2=D
凡是以 local 所定義的區域變數都只會存在於函數之中,不會影響到函數以外的全域變數。
