在 C++、Java、C#、Python 等大部分程式語言中,返回值是指函數被呼叫之後,執行函數體中的程式碼所得到的結果,這個結果就通過 return 語句返回。
但是 Shell 中的返回值表示的是函數的退出狀態:返回值為 0 表示函數執行成功了,返回值為非 0 表示函數執行失敗(出錯)了。if、while、for 等語句都是根據函數的退出狀態來判斷條件是否成立。
Shell 函數的返回值只能是一個介於 0~255 之間的整數,其中只有 0 表示成功,其它值都表示失敗。
函數執行失敗時,可以根據返回值(退出狀態)來判斷具體出現了什麼錯誤,比如一個開啟檔案的函數,我們可以指定 1 表示檔案不存在,2 表示檔案沒有讀取許可權,3 表示檔案型別不對。
如果函數體中沒有 return 語句,那麼使用預設的退出狀態,也就是最後一條命令的退出狀態。如果這就是你想要的,那麼更加嚴謹的寫法為:
return $?
$?
是一個特殊變數,用來獲取上一個命令的退出狀態,或者上一個函數的返回值,請猛擊《Shell $?》了解更多。
如何得到函數的處理結果?
有人可能會疑惑,既然 return 表示退出狀態,那麼該如何得到函數的處理結果呢?比如,我定義了一個函數,計算從 m 加到 n 的和,最終得到的結果該如何返回呢?
這個問題有兩種解決方案:
-
一種是借助全域性變數,將得到的結果賦值給全域性變數;
-
一種是在函數內部使用 echo、printf 命令將結果輸出,在函數外部使用
$()
或者``
捕獲結果。
下面我們具體來定義一個函數 getsum,計算從 m 加到 n 的和,並使用以上兩種解決方案。
【範例1】將函數處理結果賦值給一個全域性變數。
#!/bin/bash
sum=0 #全域性變數
function getsum(){
for((i=$1; i<=$2; i++)); do
((sum+=i)) #改變全域性變數
done
return $? #返回上一條命令的退出狀態
}
read m
read n
if getsum $m $n; then
echo "The sum is $sum" #輸出全域性變數
else
echo "Error!"
fi
執行結果:
1
100
The sum is 5050
這種方案的弊端是:定義函數的同時還得額外定義一個全域性變數,如果我們僅僅知道函數的名字,但是不知道全域性變數的名字,那麼也是無法獲取結果的。
【範例2】在函數內部使用 echo 輸出結果。
#!/bin/bash
function getsum(){
local sum=0 #區域性變數
for((i=$1; i<=$2; i++)); do
((sum+=i))
done
echo $sum
return $?
}
read m
read n
total=$(getsum $m $n)
echo "The sum is $total"
#也可以省略 total 變數,直接寫成下面的形式
#echo "The sum is "$(getsum $m $n)
執行結果:
1↙
100↙
The sum is 5050
程式碼中總共執行了兩次 echo 命令,但是卻只輸出一次,這是因為
$()
捕獲了第一個 echo 的輸出結果,它並沒有真正輸出到終端上。除了
$()
,你也可以使用
``
來捕獲 echo 的輸出結果,請猛擊《Shell變數》了解兩者的區別。
這種方案的弊端是:如果不使用
$()
,而是直接呼叫函數,那麼就會將結果直接輸出到終端上,不過這貌似也無所謂,所以我推薦這種方案。
總起來說,雖然C語言、C++、Java 等其它程式語言中的返回值用起來更加方便,但是 Shell 中的返回值有它獨特的用途,所以不要帶著傳統的程式設計思維來看待 Shell 函數的返回值。