Shell script 錯誤處理 (Error Handling)

Kurt
Kurt
Published in
5 min readJul 7, 2022
Photo by Gabriel Heinzer on Unsplash

文章同步發表於 個人網站,之後的文章都會發布在個人網站上,再請大家多多支持啦❤️

因最近工作需求,需要撰寫一些腳本(scripts),以往寫的腳本都偏簡單,沒有什麼複雜的情況,更不用說如果執行失敗,還要做什麼錯誤處理xD

不過這次遇到了需要處理的情況,上網查了一些資料,除了自行做紀錄以外,也分享給大家

大家除了看完文章以外,也歡迎大家把腳本片段複製下來,自己實際去執行看看結果!

特殊參數 $?

$? 可以拿到最後一個指令的返回碼,只有 0 帶表示執行成功,狀態碼請參考下表:

shell script exit code

所以我們只要在「可能」會出錯的指令後面去判斷 $? 的值是多少,就可以在這邊去決定我們要做什麼錯誤處理

以下腳本因為 a.txt 不存在,所以執行 cp a.txt b.txt 時就出錯了,因此下一行使用 echo 印出 $? 的結果,可以看到就不是 0

#!bin/bash# 實際上不存在 a.txt 檔案,所以這邊會出錯
cp a.txt b.txt
# 印出來的結果的確不是 0
echo $?
上面的腳本會印出此結果

所以我們就可以利用 $? 結果不等於 0 的情況下,寫個 if else 去做錯誤處理

#!bin/bash# 實際上不存在 a.txt 檔案,所以這邊會出錯
cp a.txt b.txt
# 先把上一個指令的結果碼用變數記下來,因為當你執行下一個指令時
# $? 的結果就會變成下一個指令的結果碼
lastResult=$?
# 如果結果不等於0,就印出 "執行失敗"
if [ $lastResult -ne 0 ]
then
echo "執行失敗"
fi

每個指令都要判斷,好麻煩 ⁉️

因為我們的 shell script 通常不會只有兩三行指令,隨著要做的事情增加,我們的 script 也會隨之變得龐大,如果我們需要在每個指令後面加上 if else 判斷是否成功,以及失敗後是否要中斷執行,這樣好像會讓 script 變得漏漏長一串,此時 set -e 指令就可以派上用場

set -e 這個指令會在任何指令失敗的時候,結束整個 script 的執行,意即:有任一指令出錯,就不會繼續執行下去

此指令等價於 set -o errexit

#!bin/bash# 實際上不存在 a.txt 檔案,所以這邊會出錯
cp a.txt b.txt
# 結果上面出錯了,還是執行到這行
echo "如果上面有錯不要執行我"
沒有 set -e 的執行結果
#!bin/bash# 加入這行,只要任一指令出錯即中斷
set -e
# 實際上不存在 a.txt 檔案,所以這邊會出錯
cp a.txt b.txt
# 上面出錯了,腳本中斷了,所以以下指令沒有被執行
echo "如果上面有錯不要執行我"
加入 set -e 的執行結果

有了這個語法,就不用在每個地方都做錯誤處理啦~

阿錯了直接離開,怎麼執行錯誤處理阿 💢

聰明的你可能會發現一些問題,如果還沒發現的朋友,可以執行下面的腳本看看!

#!bin/bashset -e# 實際上不存在 a.txt 檔案,所以這邊會出錯
cp a.txt b.txt
if [ $? -ne 0 ]
then
echo "執行失敗"
fi
上面腳本的執行結果

如果執行以上腳本,會出線上圖那個結果,看出來了嗎?

說好的錯誤處理呢???

理論上我們預期此腳本再出錯時,要印出「執行失敗」的文字,但因為我們設置了 set -e ,導致出錯後就直接結束了,後面的指令也就都執行不到了

有請 trap 指令登場 ⭐⭐⭐

簡單介紹一下 trap,trap 是 shell 內建的命令,通常用在腳本中指定信號的處理方式。trap 除了處理 Linux 信號外,還能對腳本退出(EXIT)、調試(DEBUG)、錯誤(ERR)、返回(RETURN)等以上情況指定處理方式。

簡單一句:trap 可以定義在離開腳本前要執行的指令

於是上面的那個腳本,就可以改成下方的版本:

#!bin/bashset -e# shell script 中的 function
ErrorHandling () {
if [ $? -ne 0 ]
then
echo "執行失敗"
fi
}
# 離開腳本前執行 ErrorHandling 這個 function
trap ErrorHandling EXIT
# 實際上不存在 a.txt 檔案,所以這邊會出錯
cp a.txt b.txt
以上腳本的執行結果

由以上結果可以確定,當腳本要離開前,有去執行 ErrorHandling function,在 function 裡面我們再去判斷最後一個指令的結果碼,然後再去做你要做的錯誤處理!

Follow Me On Github📌

--

--