Bash 初學(xué)者系列 9:在 bash 中使用函數(shù)
當(dāng)你的 bash 腳本中代碼非常多的時候,會看起來很混亂,其中有部分代碼有可能是重復(fù)的。這個時候,可以使用函數(shù)來避免重復(fù)的代碼。
今天我們將介紹在 bash 中如何創(chuàng)建函數(shù),以及函數(shù)中的返回值、傳遞參數(shù)等內(nèi)容。
在 bash 中創(chuàng)建函數(shù)
創(chuàng)建 bash 函數(shù)有兩種不同的語法。最常用的方法如下:?
第二種方法不太常用,如下所示:
在使用函數(shù)時,需要注意以下幾點:
- 除非被調(diào)用,否則函數(shù)永遠(yuǎn)不會被執(zhí)行;
- 函數(shù)必須先定義,然后才能被調(diào)用。
作為演示,我們創(chuàng)建一個 fun.sh 腳本,如下代碼:
上述腳本中,我們定義了一個名為 hello 的函數(shù),它將在終端上打印 Hello World。后面我們調(diào)用了三次 hello 函數(shù),因此,運行腳本后,你會在屏幕上看到 Hello World 打印了三次:
函數(shù)的返回值
在很多編程語言中,函數(shù)在調(diào)用時都會返回一個值,然而,在 bash 函數(shù)中沒有返回值。
當(dāng)函數(shù)執(zhí)行完成時,會返回一個 $? 變量作為退出狀態(tài),0 表示成功執(zhí)行,其他非零正整數(shù)(1 - 255)表示執(zhí)行失敗。
我們來寫一個例子,命名為 error.sh,在其中寫一個 return 語句,如下代碼所示:?
執(zhí)行結(jié)果如下:
因為有 return 0 這一行,所以即使函數(shù)中有 blabla 這一行的報錯,error 函數(shù)還是返回了一個執(zhí)行成功的狀態(tài)碼 0。
return 語句執(zhí)行后,函數(shù)會被立即終止。
向 bash 函數(shù)傳遞參數(shù)
我們可以向函數(shù)傳遞參數(shù),就像向?? bash 腳本傳遞參數(shù)???一樣。
作為演示,我們創(chuàng)建一個名為 iseven.sh 的腳本,如下所示:?
iseven() 函數(shù)判斷數(shù)字是偶數(shù)還是奇數(shù)。在調(diào)用的時候,將參數(shù)放在函數(shù)名后面,函數(shù)執(zhí)行的時候會讀取 $1 來獲取傳遞的參數(shù)。我們來執(zhí)行一下:
這里需要注意,bash 函數(shù)中的參數(shù),和 bash 腳本的參數(shù)需要區(qū)分開來,看如下 funarg.sh 腳本:?
執(zhí)行結(jié)果如下:
可以看到,同樣是使用 $1 和 $2 來引用腳本參數(shù)和函數(shù)參數(shù),當(dāng)實際調(diào)用時,取值是不同的。
bash 函數(shù)中的全局變量和局部變量
與大多數(shù)編程語言累死,bash 變量具有全局變量和局部變量之分。其中全局變量可以在任何位置方位到,而局部變量只能在其定義的函數(shù)中訪問。
作為演示,看如下 scope.sh 腳本:?
我們首先定義了兩個全局變量 v1 和 v2,然后在 函數(shù) myfun() 中,使用 local 關(guān)鍵字 定義了一個局部變量 v1,并修改了全局變量 v2。在不同的函數(shù)中,局部變量可以使用相同的變量名。
執(zhí)行一下,結(jié)果如下:?
由此,我們可以看到:
- 如果局部變量的變量名與全局變量的變量名相同,那么局部變量優(yōu)先級會更高;
- 在函數(shù)中可以更改全局變量的值。
遞歸函數(shù)
遞歸函數(shù)是一個調(diào)用自身的函數(shù)。階乘計算是遞歸函數(shù)的經(jīng)典例子,看下面的腳本 factorial.sh:
任何遞歸函數(shù)都要從一個基本條件開始,這個基本條件必須可以結(jié)束遞歸函數(shù)調(diào)用鏈。在 factorial() 函數(shù)中,基本條件為:
然后導(dǎo)出階乘函數(shù)的遞歸情況。要計算 n 的階乘,其中 n 是大于 1 的正數(shù),可以將 n 乘以 n-1 的階乘:
使用上面那個公式來編寫遞歸函數(shù)的算法:?
然后運行一下,檢查運行結(jié)果: