如果秉承著能跑就行的態度寫shell腳本,是很自在的,但是如果你想要寫出健壯,可靠的shell腳本,可沒那麼容易。那麼有什麼可操作的經驗或者方法嗎?
語法檢查
第一個最簡單的方法就是利用工具對腳本進行檢查,這一部分已經在《有了這個神器,再也不怕shell寫不對了》中介紹過了,它能最大程度地發現shell腳本中存在的語法錯誤,如果你還不知道,建議你絕對不要錯過。
而為了保證腳本健壯可靠,那麼就需要保證腳本在一些特殊的情況及早出現,避免漏網之魚。來看看有哪些可行的技巧。
腳本失敗時即退出
可以在腳本的開頭設置如下:
<code>set -e/<code>
舉個例子:
<code>#!/bin/bash
set -e
lp #這裡運行會出錯
date/<code>
這種情況下,運行一旦出錯就會退出,不放過一個問題:
<code>$ ./test.sh
lp: Error - no default destination available./<code>
當然了,這也有不好的地方,有時候命令執行本來就可能是失敗的,你還是希望它繼續,可以臨時加上|| true:
<code>#!/bin/bash
set -e
lp || true
date/<code>
不過個人覺得這樣的設置用處不是特別大,因為很多時候就是需要處理不同的錯誤情況,而這樣只能要麼遇到錯誤退出,要麼認為正確,導致無法走到異常分支。通過set +e設置回來:
<code>set -e
#command
set +e
#other command/<code>
打印腳本執行過程
調試階段,你可能想知道整個過程是執行了哪些命令,每條命令都具體執行了什麼,可以利用下面的方式執行:
<code>sh -x test.sh/<code>
或者,和上面類似,在開頭加上set -x:
<code>//來源:公眾號【編程珠璣】
//作者:守望先生
#!/bin/bash
set -x
if [ $# -lt 1 ]
then
echo "no para"
else
echo "para 1 $1"
fi/<code>
執行時,輸出如下:
<code>+ [ 0 -le 1 ]
+ echo no para
no para/<code>
前面帶+的內容就是命令實際執行的,你可以看到比較條件是什麼,變量被展開成了具體內容,走到了哪個分支,非常清楚。
顯示未定義的變量
shell中變量沒有定義,仍然是可以使用的,但是它的結果可能不是你所預期的。舉個例子:
<code>//來源:公眾號【編程珠璣】
//作者:守望先生#!/bin/bash
if [ "$var" = "abc" ]
then
echo " not abc"
else
echo " abc "
fi/<code>
這裡本來想判斷var的內容是否為abc,實際上var並沒有定義,但是在這裡使用並沒有報錯,如果我們想早點發現這類問題,避免在複雜的腳本中問題被掩蓋,那麼可以在開頭加上:
<code>set -u/<code>
再次運行就會提示:
<code>test.sh: 5: test.sh: num: parameter not set/<code>
再想象一下,你本來想刪除:
<code>rm -rf $dir/*/<code>
然後dir是空的時候,變成了什麼?
是不是有種後背發涼的感覺?
管道命令一個失敗時整個失敗
有時候我們可能會執行類似這樣的命令:
<code>cat test.sh |grep if | cut -d ';' -f 2/<code>
三條命令一行執行,如果我們希望在其中一條失敗,整個命令就失敗,而避免執行後面無意義的命令,那麼可以在開始設置:
<code>set -o pipefail/<code>
不設置的情況下,cat test.sh即使執行失敗了,後面的grep實際上還會繼續執行,可能會導致一些意想不到的情況發生,如果不想這樣的情況發生,那麼這樣設置是有幫助的。
對於靜態變量使用readonly
通常我們會在腳本開頭定義一些靜態變量:
<code>MY_PATH=/usr/bin/<code>
而為了避免MY_PATH被意外修改,可以這樣:
<code>readonly MY_PATH=/usr/bin/<code>
這樣的話,一旦後面有命令嘗試修改,就會報錯。
<code>#!/bin/bash
readonly MY_PATH=/usr/bin
MY_PATH=/usr/local/bin/<code>
運行一下試試:
<code>$ ./test.sh
test.sh: 3: test.sh: MY_PATH: is read only/<code>
看,給你提示了!
給變量設置可選的初始值
例如:
<code>name=${1:-shouwang}
echo "${name}"/<code>
這裡讓name為$1,即第一個參數,而當它為空時,令name為shouwang。
多條命令執行使用&&
例如:
<code>cmd0;cmd1;cmd1/<code>
這裡如果cmd0失敗了,後面的命令仍然會執行,而如果不希望後面的命令執行,可以使用:
<code>cmd0 && cmd1 && cmd1/<code>
使用函數
腳本本身比較短還好,而腳本一旦變長,不使用函數,將使得腳本很難維護,可讀性也很差。
總結
實際上最開始介紹的腳本檢查工具就已經非常有效了,基本的錯誤都能檢查出來,而其他的內容,更多的是關注於腳本調試,不放過任何一個可能的錯誤。
最後,還是優先推薦shellcheck工具。
關注公眾號【編程珠璣】,獲取更多Linux/C/C++/數據結構與算法/計算機基礎/工具等原創技術文章。後臺免費獲取經典電子書和視頻資源
閱讀更多 守望的編程珠璣 的文章