2013-02-20 59 views
11

我有點困惑在這裏。我的目標是在腳本中的任何命令失敗時使bash腳本以非零退出代碼退出。使用-e標誌,我認爲這將是這種情況,即使使用子殼。下面是一個簡單的例子:爲什麼bash標誌-e在子殼失敗時退出?

#!/bin/bash -e 

(false) 

echo $? 
echo "Line reached!" 

這裏是輸出時跑:

[$]>Tests/Exec/continuous-integration.sh 
1 
Line reached! 

猛砸版本:3.2.25在CentOS

+0

是否有機會在所有你可以更新你的bash版本,因爲這個確切的腳本按照4.1.5的預期工作。也許這是你的'FALSE'版本 – 2013-02-20 01:17:53

回答

8

看來好像這是關係到你的版本bash。在我有權訪問的機器上,bash版本3.1.17和3.2.39顯示了這種行爲,但bash 4.1.5沒有。

雖然有點難看,在這兩個版本的有效的解決方案可能是這樣的:

#!/bin/bash -e 

(false) || exit $? 

echo $? 
echo "Line reached!" 

有其中涉及與set -e選項錯誤bash的源更新日誌的一些注意事項。

+0

啊,感謝的挖掘,這是它!感謝您的建議答案,這正是我將要做的。 – 2013-02-20 01:53:21

+1

不知道操作系統OP是在哪,但例如不幸的是,山獅仍然隨着bash 3一起出貨。 – 2013-02-20 02:29:34

0

我看到的這兩個的SuSE 11.3和Mac OS之前,埃爾卡皮坦在bash版51年2月3日此行爲。在埃爾卡皮坦猛砸3.2.57有「正確」的行爲,即諸如bash 4.

然而,上面提出的解決辦法,增加「||退出$?」在子shell的關閉paren之後,無論使用什麼版本的bash,都會打敗-e標誌的意圖。從男子bash:

-e如果一個簡單的命令(見上面的SHELL GRAMMAR)退出 非零狀態立即退出。如果失敗的命令是命令列表的 部分緊跟一段時間,或直到關鍵字,在測試過程中 在if語句,一個& &或部分shell不會退出||列表,...

子shell後跟「|| exit $?」顯然算作命令清單;並且bash -e標誌不適用於子shell內的ANY命令。試試看:

$ set -e 
$ (echo before the error; false; echo after the error, status $?;) || echo after the subshell, status $? 
before the error 
after the error, status 1 
$ 

因爲子shell之後||,即運行,即使設定-e「的錯誤後回聲」。不僅如此,subshel​​l退出0,因爲「回聲」跑了。那麼「|| exit $?」甚至不會運行「退出」。可能不是我們想要的!

所以,據我所知,他們是否兌現慶典-e子shell後,還是沒有下面的公式是使用bash版本兼容。它甚至能夠正常運作,如果-e標誌恰巧被重置:

添加以下行的每個子shell在bash腳本右括號後:

case $?/$- in (0/*) ;; (*/*e*) exit $? ;; esaC# honor bash -e flag when subshell returns