Bash
什麼時候inherit_errexit 不起作用?
#!/usr/bin/env bash set -e shopt -s inherit_errexit a=$(cat no-such-file) echo survived
$ /tmp/a.sh cat: no-such-file: No such file or directory
#!/usr/bin/env bash set -e shopt -s inherit_errexit echo -n $(cat no-such-file) echo survived
$ /tmp/a.sh cat: no-such-file: No such file or directory survived
#!/usr/bin/env bash set -e shopt -s inherit_errexit f() { :; } f $(cat no-such-file) echo survived
$ /tmp/a.sh cat: no-such-file: No such file or directory survived
還有其他情況嗎?還是某種概括?
TL,DR:為了受益
set -e
,直接將命令替換的結果分配給變數(可選地在其周圍加上額外的字元串)。不要將多個命令替換組合在一起或在命令參數中使用命令替換。問題不在於
inherit_errexit
. 它正在工作。問題是set -e
(不是特定於 bash 的限制:其他類似 sh 的 shell 也有同樣的問題)。展示:執行第二個範例的這個變體。
$ cat b2.sh #!/usr/bin/env bash set -e shopt -s inherit_errexit echo -n $(cat no-such-file; echo >&2 after cat) echo survived $ ./b2.sh cat: no-such-file: No such file or directory survived
請注意,
echo >&2 after cat
未執行。如果inherit_errexit
是關閉的,那將是。問題是
set -e
僅在簡單情況下停止執行錯誤。如果命令替換返回失敗狀態,則不會停止執行包含替換的簡單命令。它最多可能會設置簡單命令的返回狀態,這反過來可能會停止腳本的執行。“簡單命令”由賦值、重定向和可選的可執行命令名稱和參數組成。如果重定向失敗,則返回狀態為1。否則,如果有命令名,則簡單命令的返回狀態為可執行命令的返回狀態。否則返回狀態是最後一個命令替換的返回狀態,如果沒有,則返回 0。以下是一些簡單命令的範例:
true </no/such/file
→ 狀態 1 由於重定向失敗false </dev/null
→ 狀態 1 從false
a=b
→ 狀態 0,因為沒有任何可能失敗的部分a=$(exit 0) b=$(exit 1) c=$(exit 2)
→ 上次命令替換的狀態 2a=$(exit 2) b=$(exit 1) c=$(exit 0)
→ 上次命令替換的狀態 0true $(exit 0) $(exit 1) $(exit 2)
→ 狀態 0 從true
再一次,在所有情況下,
set -e
僅當命令的狀態為非零時才會停止腳本。嵌入式命令的狀態不直接相關。因此,在您的第二個腳本
echo -n $(…)
中,狀態為 0,來自echo
(除非echo
無法寫入),無論命令替換內部發生什麼。因此,即使set -e
處於活動狀態,腳本也不會在這裡停止。同樣,在第三個腳本f $(…)
中,狀態為 0 來自f
.