函數
和大多數編程語言一樣,shell 腳本也支持函數。在 shell 可以用下面的方式定義和使用函數:
#!/bin/bash
# 定義函數
sayHello () {
echo "hello $1"
}
# 調用函數並傳遞參數
sayHello jack
上面的例子將輸出“hello jack”。shell 中雖然也有函數的概念,但和 c、php、js 等編程語言中函數不太一樣,shell 腳本中的函數更像是注入在主 shell 腳本中的一段子腳本,調用函數就像是運行這段子腳本,但它不是在新的進程中運行,所以可以和主 shell 腳本共享變量和函數。函數也可以像 shell 腳本那樣通過 $0、$1 等變量獲取參數。還要注意 shell 函數的調用一定要在函數定義之後,解釋器是順序解析的,在函數定義之前調用函數將報錯。
另外,就像 shell 腳本通過 exit code 返回狀態碼那樣,函數也可以通過 return code 的方式返回一個狀態碼。但要注意狀態碼不是文本數據,無法輸出,想要返回文本數據可以在函數中 echo 文本數據,再通過反引號或 $() 的方式解析,例如:
#!/bin/bash
# 函數返回狀態碼
getCode() {
return 0
}
code=`getCode`
echo $code
# 輸出爲空
# 函數返回文本值
getData () {
echo "some text"
}
data=`getData`
echo "data is $data"
# 輸出爲 data is some text
最後 shell 函數也支持嵌套和遞歸調用,讓我們可以實現一些複雜的算法邏輯,當然這樣會比較吃資源。
#!/bin/bash
# shell 遞歸實現斐波那契數列
fibo () {
# 獲取參數,即想輸出數列的第幾個值
index=$1
# index 爲 1 或 2 時值爲 1
# 用 -lt 選項進行數字小於比較,具體請參考 test 命令幫助
if [ $index -lt 3 ]; then
echo 1
else
# index 大於等於 3 時數列值爲前兩項的和
# 注意 shell 中變量都爲字符串類型,要藉助 expr 命令進行數字計算
n1=`expr $index - 1`
n2=`expr $index - 2`
expr `fibo n2` + `fibo n1`
fi
}
# 調用函數求斐波那契數列第 10 項的值
fibo 10
作用域
談到函數當然逃不開作用域。在 shell 腳本中默認所有的變量都在全局作用域下,也就是全局變量。想要只在函數中有效的局部變量可以用 local 來聲明。
#!/bin/bash
# 變量作用域
func () {
# 變量 val1 默認在全局作用域下
val1=123
# 用 local 聲明變量 val2 爲局部變量
local val2=456
echo "val1 in func is $val1"
echo "val2 in func is $val2"
}
func
echo "val1 outsite is $val1"
echo "val2 outsite is $val2"
# 運行結果
# val1 in func is 123
# val2 in func is 456
# val1 outside is 123
# val2 outside is
使用 getopts
getopts 是 shell 內建的一個命令,它可以用來檢查和獲取傳遞給命令的選項和參數。它的用法如下
#!/bin/bash
# getopts 獲取選項和參數
# 腳本 getopts.sh
# getopts 的語法爲 getopts opstring name
# opstring 中可以指定腳本接受哪些選項,如果選項必須提供參數就在後面加冒號
# 例如下面的 'xy:z:' 表示腳本接受 -x -y -z 選項且 -y -z 選項必須提供參數
# name 是一個 shell 變量用來保存選項
# getopts 還通過 $OPTIND 保存參數的索引,$OPTARG 保存參數的值
while getopts 'xy:z:' name; do
echo "$name" $OPTIND $OPTARG
done
# shell
./getopts.sh -xy "one" -z "two"
# 運行結果
# x 1
# y 3 one
# z 5 two
由於函數也可以看作是一段腳本,所以 getopts 命令也可以用在函數中來判斷和獲取函數接受的選項和參數。
函數庫
如果我們有一些通用的函數或處理在很多地方都用的上,那麼最好將他們做成庫文件供其他腳本調用。類似 php 的 include,shell 腳本想要包含其他腳本或者說是庫文件也很簡單,用 . 操作符就行了,點後面跟腳本文件名就可以運行指定的腳本,它們不是另起進程而是在同一進程下運行,所以可以共享變量和函數定義,這樣就實現了函數庫的效果。
例如下面的代碼將腳本 lib.sh 包含到當前腳本中,注意 . 操作符後面要有一個空格。另外也可以通過 source 來包含庫文件,與 . 操作符效果相同。
#!/bin/bash
# 將指定的腳本文件包含到當前腳本
. /root/lib/lib.sh
# 用 source 命令可以達到相同的目的
source /root/lib/lib.sh
# 包含之後就可以使用 lib.sh 中定義的變量和函數了