本文將介紹Bash中 set -euxo pipefail
,它們可以幫助你寫出更容易維護也更安全的腳本。這也是Bash腳本的終極調試手段。
set -e
set -e
選項可以讓你的腳本在出現異常時馬上退出,后續命令不再執行。默認情況下Shell腳本不會因為錯誤而結束執行,但大多數情況是,我們希望出現異常時就不要再往下走了。假如你的if
判斷條件里會出現異常,這時腳本也會直接退出,但可能這並不是你期望的情況,這時你可以在判斷語句后加上 || true
來阻止退出。
Before
#!/bin/bash # 'foo' is a non-existing command foo echo "bar" # output # ------ # line 4: foo: command not found # bar
After
#!/bin/bash set -e # 'foo' is a non-existing command foo echo "bar" # output # ------ # line 5: foo: command not found
阻止立即退出的例子。
#!/bin/bash set -e # 'foo' is a non-existing command foo || true echo "bar" # output # ------ # line 5: foo: command not found # bar
set -o pipefail
默認情況下Bash只會檢查管道(pipeline)操作最后一個命令的返回值,假如最右邊的命令成功那么它就認為這個語句沒問題。這個行為其實是很不安全的,所以就有了set -o pipefail
。這個特別的選項表示在管道連接的命令中,只要有任何一個命令失敗(返回值非0),則整個管道操作被視為失敗。只有管道中所有命令都成功執行了這個管道才算成功執行。
Before
#!/bin/bash set -e # 'foo' is a non-existing command foo | echo "a" echo "bar" # output # ------ # a # line 5: foo: command not found # bar
After
#!/bin/bash set -eo pipefail # 'foo' is a non-existing command foo | echo "a" echo "bar" # output # ------ # a # line 5: foo: command not found
set -u
set -u
比較容易理解,Bash會把所有未定義的變量視為錯誤。默認情況下Bash會將未定義的變量視為空,不會報錯,這也是很多坑的來源。也許由於變量名的細微差別讓你查半天最后罵罵咧咧。
Before
#!/bin/bash set -eo pipefail echo $a echo "bar" # output # ------ # # bar
After
#!/bin/bash set -euo pipefail echo $a echo "bar" # output # ------ # line 5: a: unbound variable
set -x
set -x
可以讓Bash把每個命令在執行前先打印出來,你可以認為這就是Bash的Debug開關。它的好處當然顯而易見,方便你快速找到有問題的腳本位置,但是也壞處也有吧,就是Bash的log會格外的亂。另外,它在打印命令前會把變量先解析出來,所以你可以知道當前執行的語句的變量值是什么。縱然log可能會亂一些,總比頭發亂一些好,所以建議還是打開這個開關。
#!/bin/bash set -euxo pipefail a=5 echo $a echo "bar" # output # ------ # + a=5 # + echo 5 # 5 # + echo bar # bar