因最近工作需求,需要撰寫一些腳本(scripts),以往寫的腳本都偏簡單,沒有什麼複雜的情況,更不用說如果執行失敗,還要做什麼錯誤處理xD
不過這次遇到了需要處理的情況,上網查了一些資料,除了自行做紀錄以外,也分享給大家
大家除了看完文章以外,也歡迎大家把腳本片段複製下來,自己實際去執行看看結果!
特殊參數 $?
$? 可以拿到最後一個指令的返回碼,只有 0 帶表示執行成功,狀態碼請參考下表:
所以我們只要在「可能」會出錯的指令後面去判斷 $? 的值是多少,就可以在這邊去決定我們要做什麼錯誤處理
以下腳本因為 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 "如果上面有錯不要執行我"
#!bin/bash# 加入這行,只要任一指令出錯即中斷
set -e# 實際上不存在 a.txt 檔案,所以這邊會出錯
cp a.txt b.txt# 上面出錯了,腳本中斷了,所以以下指令沒有被執行
echo "如果上面有錯不要執行我"
有了這個語法,就不用在每個地方都做錯誤處理啦~
阿錯了直接離開,怎麼執行錯誤處理阿 💢
聰明的你可能會發現一些問題,如果還沒發現的朋友,可以執行下面的腳本看看!
#!bin/bashset -e# 實際上不存在 a.txt 檔案,所以這邊會出錯
cp a.txt b.txtif [ $? -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📌