shell腳本在運行異常時會受到非常大的影響。
本文介紹一些讓bash腳本變得健壯的技術。
使用set -u
因為沒有對變量初始化而使腳本崩潰過多少次?對于我來說,很多次。
chroot=$1
...
rm -rf $chroot/usr/share/doc
如果上面的代碼沒有給參數就運行,不會僅僅刪除掉chroot中的文檔,而是將系統的所有文檔都刪除。那應該做些什么呢?好在bash提供了set -u,當使用未初始化的變量時,讓bash自動退出。
也可以使用可讀性更強一點的set -o nounset。
 代碼如下:
david% bash /tmp/shrink-chroot.sh
$chroot=
david% bash -u /tmp/shrink-chroot.sh
/tmp/shrink-chroot.sh: line 3: $1: unbound variable
david%
使用set -e
寫的每一個腳本的開始都應該包含set -e。這告訴bash一但有任何一個語句返回非真的值,則退出bash。使用-e的好處是避免錯誤滾雪球般的變成嚴重錯誤,能盡早的捕獲錯誤。更加可讀的版本:set -o errexit
使用-e把從檢查錯誤中解放出來。如果忘記了檢查,bash會替做這件事。不過也沒有辦法使用$?來獲取命令執行狀態了,因為bash無法獲得任何非0的返回值。可以使用另一種結構:
command
if [ "$?"-ne 0]; then echo "command failed"; exit 1; fi
可以替換成:
command || { echo "command failed"; exit 1; }
或者使用:
if ! command; then echo "command failed"; exit 1; fi
如果必須使用返回非0值的命令,或者對返回值并不感興趣呢?可以使用 command || true ,或者有一段很長的代碼,可以暫時關閉錯誤檢查功能,不過我建議謹慎使用。
set +e
command1
command2
set -e
相關文檔指出,bash默認返回管道中最后一個命令的值,也許是不想要的那個。比如執行 false | true 將會被認為命令成功執行。如果想讓這樣的命令被認為是執行失敗,可以使用 set -o pipefail
程序防御 - 考慮意料之外的事
的腳本也許會被放到“意外”的賬戶下運行,像缺少文件或者目錄沒有被創建等情況??梢宰鲆恍╊A防這些錯誤事情。比如,當創建一個目錄后,如果父目錄不存在,mkdir 命令會返回一個錯誤。如果創建目錄時給mkdir命令加上-p選項,它會在創建需要的目錄前,把需要的父目錄創建出來。另一個例子是rm 命令。如果要刪除一個不存在的文件,它會“吐槽”并且的腳本會停止工作。(因為使用了-e選項,對吧?)可以使用-f選項來解決這個問題,在文件不存在的時候讓腳本繼續工作。
準備好處理文件名中的空格
有些人從在文件名或者命令行參數中使用空格,需要在編寫腳本時時刻記得這件事。需要時刻記得用引號包圍變量。
if [ $filename = "foo" ];
當$filename變量包含空格時就會掛掉??梢赃@樣解決:
新聞熱點
疑難解答