介紹如何在 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
所定義的區域變數都只會存在於函數之中,不會影響到函數以外的全域變數。
參考資料:鳥哥的 Linux 私房菜、GNU、Linuxize