所謂模組化,就是把程式碼分散到多個檔案或者資料夾。對於大中型專案,模組化是必須的,否則會在一個檔案中堆積成千上萬行程式碼,這簡直是一種災難。
基本上所有的程式語言都支援模組化,以達到程式碼複用的效果,比如,Java 和 Python 中有 import,C/C++ 中有 #include。在 Shell 中,我們可以使用 source 命令來實現類似的效果。
在《執行Shell指令碼》一節中我們已經提到了 source 命令,這裡我們再來講解一下。
source 命令的用法為:
source filename
也可以簡寫為:
. filename
兩種寫法的效果相同。對於第二種寫法,注意點號
.
和檔名中間有一個空格。
source 是 Shell 內建命令的一種,它會讀取 filename 檔案中的程式碼,並依次執行所有語句。你也可以理解為,source 命令會強制執行指令碼檔案中的全部命令,而忽略指令碼檔案的許可權。
範例
建立兩個指令碼檔案 func.sh 和 main.sh:func.sh 中包含了若干函數,main.sh 是主檔案,main.sh 中會包含 func.sh。
func.sh 檔案內容:
#計算所有引數的和
function sum(){
local total=0
for n in [email protected]
do
((total+=n))
done
echo $total
return 0
}
main.sh 檔案內容:
#!/bin/bash
source func.sh
echo $(sum 10 20 55 15)
執行 main.sh,輸出結果為:
100
source 後邊可以使用相對路徑,也可以使用絕對路徑,這裡我們使用的是相對路徑。
避免重複引入
熟悉 C/C++ 的讀者都知道,C/C++ 中的標頭檔案可以避免被重複引入;換句話說,即使被多次引入,效果也相當於一次引入。這並不是 #include 的功勞,而是我們在標頭檔案中進行了特殊處理。
Shell source 命令和 C/C++ 中的 #include 類似,都沒有避免重複引入的功能,只要你使用一次 source,它就引入一次指令碼檔案中的程式碼。
那麼,在 Shell 中究竟該如何避免重複引入呢?
我們可以在模組中額外設定一個變數,使用 if 語句來檢測這個變數是否存在,如果發現這個變數存在,就 return 出去。
這裡需要強調一下 return 關鍵字。return 在 C++、C#、Java 等大部分程式語言中只能退出函數,除此以外再無他用;但是在 Shell 中,return 除了可以退出函數,還能退出由 source 命令引入的指令碼檔案。
所謂退出指令碼檔案,就是在被 source 引入的指令碼檔案(子檔案)中,一旦遇到 return 關鍵字,後面的程式碼都不會再執行了,而是回到父指令碼檔案中繼續執行 source 命令後面的程式碼。
return 只能退出由 source 命令引入的指令碼檔案,對其它引入指令碼的方式無效。
下面我們通過一個範例來演示如何避免指令碼檔案被重複引入。本例會涉及到兩個指令碼檔案,分別是主檔案 main.sh 和 模組檔案 module.sh。
模組檔案 module.sh:
if [ -n "$__MODULE_SH__" ]; then
return
fi
__MODULE_SH__='module.sh'
echo "http://c.biancheng.net/shell/"
注意第一行程式碼,一定要是使用雙引號把
$__MODULE_SH__
包圍起來,具體原因已經在《Shell test》一節中講到。
主檔案 main.sh:
#!/bin/bash
source module.sh
source module.sh
echo "here executed"
./
表示當前檔案,你也可以直接寫作
source module.sh
。
執行 main.sh,輸出結果為:
http://c.biancheng.net/shell/
here executed
我們在 main.sh 中兩次引入 module.sh,但是只執行了一次,說明第二次引入是無效的。
main.sh 中的最後一條 echo 語句產生了輸出結果,說明 return 只是退出了子檔案,對父檔案沒有影響。