Shell 腳本中的函數

通過之前發表的文章,相信大家對 Linux Shell 腳本的基本語法有了一定程度的瞭解,接下來幾篇文章我將會介紹一些 Shell 腳本編程的一些高級語法,今天我們就從函數開始。

提到函數,相信有過編程基礎的小夥伴都會了解一些,函數其實是我們編碼的邏輯單元,無論我們用的面向過程的語言,還是面向對象的語言,函數都是編程中基本的內容。好的函數接口設計,清晰的函數邏輯,巧妙的函數提取,都是對程序員最基本的要求。

創建函數

bash shell中有兩種方式創建函數;

1. 通過function 命名函數,格式為

function name {
commands
}
Shell 腳本中的函數

圖1

2. 直接通過函數名來創建函數,格式為

name ( ) {
commands
}
Shell 腳本中的函數

圖2

圖1和圖2的輸出結果相同,為:

./my_script
this is function
this is function

注:在調用函數之前,函數首先要被定義過,也就是說在腳本編寫過程中,函數應該在調用之前先被定義,否則會出現函數未定義的錯誤。其次同名函數如果重複定義,後定義的函數會覆蓋之前定義的同名函數。

函數返回值

有時我們在調用函數式,需要通過函數的返回值來判斷接下來程序的邏輯,在bash shell中函數通過退出狀態碼(退出狀態碼的定義在之前的文章中有介紹)實現函數返回值,並且提供了3種方式來返回函數的退出狀態碼。

1. 默認退出狀態碼:

默認狀態下,函數通過最後一行命令的返回狀態碼作為整個函數的狀態碼返回。這種方式比較危險,可能函數中某些步驟的命令已經出錯了,但是最後一行的命令卻執行成功,此時作為整個函數的返回碼是正確定,那麼就掩蓋掉錯誤了。

2. 使用return 語句

可以在函數尾部通過return 語句返回自定義的返回碼,例如

function my_func {
value=1
echo "It is my function"
return $[$value+2]
}

my_func 函數返回狀態碼為3. 用return 返回狀態碼要注意,

  • 函數調用後要立即獲取返回狀態碼
  • 狀態碼的取值範圍為: 0~255。

3. 通過 echo 內容作為函數返回

Shell 腳本中的函數

圖3

如上圖,函數中通過 echo 將其後的內容做為返回值,調用函數後,會將輸入的數值翻倍後作為函數輸出保存到變量 result 中。

向函數中傳遞參數

bash shell 函數可以理解為小型腳本,之前的文章中我講解過如何向腳本中傳遞參數,所以類似的,向函數中傳遞參數的方式是一樣的。格式為

func1 $param1 $param2...

直接上例子:

Shell 腳本中的函數

圖4

之前向腳本傳遞參數的講解中,講解了如何在腳本中獲取參數值,其格式和函數獲取參數值得方式一致,通過$0, $1.. 或去對應參數的值,$#獲取參數個數。上面的例子中,通過$#判斷函數參數個數,如果大於2個或者等於0個,則認為調用失敗,返回-1 的狀態碼。如果參數是1個,則打印這個參數,如果參數剛好2個,則打印兩個參數的和。對腳本參數傳遞有印象的小夥伴可能會有些疑慮,因為函數獲取參數值的方式和腳本獲取參數值得方式相同,都是通過 $1, $2 ... 來獲取第一個,第二個參數的,那麼函數的參數會不會覆蓋腳本的參數呢?其實這裡涉及到作用域的概念,可以裂解為同名但作用域不同。舉例:

Shell 腳本中的函數

圖5

如上圖5, 函數 addem 中通過 $1, $2 來獲取傳入函數的參數值,函數體外,腳本通過$# 來獲取傳入腳本的參數個數,然後在then 語句後,通過$1, $2 來獲取傳遞到腳本的參數,然後再將傳遞進腳本的參數通過調用函數 addem 傳遞進函數體內。雖然都是通過環境變量 $1, $2 來獲取的參數,但是兩個變量作用域並不相同,你可以把函數理解為腳本文件中的子腳本。所以沒有問題。調用結果如下圖6:

Shell 腳本中的函數

圖6

變量的作用域

函數中使用的變量有兩種類型:

  • 全局變量
  • 局部變量

全局變量:顧名思義就是腳本中和函數體內都可以引用的變量。默認情況下,腳本中,函數體外定義的任何變量都是全局變量,函數體內可以直接訪問。例如

function my_func {
value=$[ $value + 5]
}
value=2
my_func
echo "The new value is: $value"

#調用腳本
輸出結果為:
The new value is: 7

上面的例子中,value 在函數體外定義了,是全局變量,所以value值被改變了,在函數體內修改全局變量並不是一個好的主意,所以函數內使用全局變量要特別注意,否則可能會引起錯誤。

局部變量:函數體內任何變量都可以聲明為局部變量,只需要在聲明前加上 local 關鍵字即可。格式為:

local tmpVar

上例子

Shell 腳本中的函數

圖7

輸出為:

local value is: 20
the global value is: 10

從結果可以看出,局部變量 variable 的修改沒有影響到全局變量的值。

數組作為函數參數

傳遞數組給函數,不能講數組變量作為單獨一個變量直接傳遞給數組,那樣只會函數內只能方位到數組的第一個元素,這個原理和C/C++有些相似,C/C++中傳遞的是數組的指針,所以也只能訪問到數組的第一個元素。bash shell 中可以通過將數組分解成單個的值進行傳遞。直接上例子:

Shell 腳本中的函數

圖8

輸出結果為:

the original array is 1 2 3 4 5
the sum result is: 15

數組作為函數返回

Shell 腳本中的函數

圖9

輸出為:

the original array is: 1 2 3 4 5
the new array is: 2 4 6 8 10

從圖9看出,函數接受數組,並將數組中所有元素翻倍後返回。

創建庫

在C/C++工程中,我們經常會將一些通用的函數放到獨立的工程中,並將其生成庫文件,也就是 lib 文件或者 dll 文件,這樣一段函數就可以被不同工程調用,從而減少代碼重複。bash shell 中也有類似的庫應用,可以將函數創建成庫文件,然後被不同的腳本調用。bash shell 中創建庫文件的步驟如下:

1. 創建包含所需函數的腳本文件,如下圖,創建一個名為 mylib 的庫文件

Shell 腳本中的函數

名字為 mylib 的庫文件

2. 在腳本中引用庫文件,可以通過source 命令引入庫文件到腳本中,source 有一個快捷別名,稱為點操作符(dot operator),下圖舉例腳本中如何引用庫文件。

Shell 腳本中的函數

圖10

圖10 為腳本文件,通過點操作符引入庫文件,調用mylib中的addem 函數。


分享到:


相關文章: