以下腳本存在語法錯誤或某種類型的錯誤:
#!/usr/bin/env bash
set -euo pipefail
if [ ! -f /custom.log]; then
echo "test"
fi
abcxyz
該腳本失敗並輸出:
./test.sh: line 4: [: missing `]'
./test.sh: line 7: abcxyz: command not found
我不關心如何修復此腳本,但如果遇到此錯誤,該如何阻止腳本進一步繼續?我以為set -e
會強制執行這種行為。
答案1
set -e
不會在用作條件的命令失敗時觸發,例如//if
建構的條件部分或 a 的左側,或在這些條件下呼叫的函數、子 shell、原始檔、ed 程式碼中。while
until
||
&&
eval
如果確實如此,那麼:
if [ ! -f /custom.log ]; then
/custom.log
如果是常規文件,則將退出腳本,[
然後也會以非零退出狀態退出。
如果不滿足測試條件,並且存在語法錯誤(但並非所有語法錯誤,例如,不在 中),則shell[
的內建命令(bash
以及大多數其他實作)將以狀態退出。1
2
[ -v 'a[+]' ]
POSIX 要求退出狀態大於 1,以防出現錯誤。
因此,如果命令以大於 1 的程式碼退出,則無論是否在條件中使用,您都可以選擇退出腳本,例如:
shopt -s extdebug # make sure the DEBUG trap propagates to subshells
trap '(($?>1 && (ret=$?))) && exit "$ret"' DEBUG
[ -f / ] || echo / not a regular file # OK
[ -f /] || echo was a syntax error # causes an exit, not output
echo not reached
請注意,您不能ERR
為此使用陷阱,因為ERR
陷阱僅在與觸發退出的條件相同的條件下運行set -e
。
現在,請注意其中的影響。例如,這會導致:
if grep -qs pattern /file; then
echo pattern was found in /file
fi
/file
如果不存在或不可讀則退出,grep
在這種情況下返回狀態為 2,即使使用-s
,其意圖顯然是忽略這些情況。
因此,您需要注意在哪些條件下您在條件中使用的命令可能會以大於 1 的狀態退出。
if sh -c 'grep -sq pattern / file || exit 1'; then...
您可以限制退出狀態大於 1 時退出到[
ortest
命令,例如:
unset -v previous_BASH_COMMAND
trap '
case $previous_BASH_COMMAND in
("[ "* | "test "*) (($?>1 && (ret=$?))) && exit "$ret"
esac
previous_BASH_COMMAND=$BASH_COMMAND' DEBUG
這有一些限制。在
echo x
([ -f/]; echo y)
這將導致子 shell 退出,但不會導致父 shell 退出,因為$previous_BASH_COMMAND
尚未在那裡設定。並在:
[ -f / ] && echo a regular file
(grep -qs foo /file && echo foo in /file)
echo here
shell 將在運行時退出echo here
,因為$?
will 是 2 且$previous_BASH_COMMAND
was [ -f / ]
。
無論如何,像這樣的事情
[ -f /] | cat
export var="$([ -f /])"
無法偵測到退出狀態,因為退出狀態不會傳播到父 shell 進程(pipefail
第一種情況下的選項除外)。
現在,我不確定是否值得在運行時添加這種(脆弱的)檢測,因為在開發時(編寫和測試腳本時)很容易檢測到錯誤。