2014-06-27 46 views
6

在要執行的shell腳本中,我可以使用set -e來中止錯誤。Bash:在源腳本中出錯時停止

但是,在源腳本中,如果稍後的命令以錯誤狀態退出,則使用set -e將終止原始shell。

source set_e.sh 
./exit_1.sh 
# shell dies 

一個平凡的解決辦法是set +e在腳本的末尾,但是這樣會破壞父母的set -e如果使用的話(如果有人包裝我的腳本,將來這很可能發生)。

如何在源腳本中獲得異常中止功能?

+0

@BlueMoon OP的帖子解釋了爲什麼不行。 –

+0

難道你不能在呼叫環境中設置退出陷阱並在那裏處理它? –

回答

0

如果errexit選項設置在源腳本的開頭並在源腳本結尾恢復其原始值,則可以通過set -o進行檢測。

2

您可以檢查是否set -e已經啓用,並有條件地設置其算賬:

[[ $- == *e* ]] && state=-e || state=+e 
set -e 
yourcode 
set "$state" 

但是請注意,這是set -e車和腳本不應該依賴於它的正確性。例如,如果有人源腳本在if聲明,set -e可能無法再正常工作:

ls: cannot access file.that.doesnt.exist: No such file or directory 
Success 
Done 

同時:

echo ' 
set -e 
ls file.that.doesnt.exist 
echo "Success" 
' > yourscript 

set -e 
if ! source yourscript 
then 
    echo "Initialization failed" 
fi 
echo "Done" 

然後set -e將不再失敗在bash 30年3月4日中止在yourscript它將在bash 2,3和4.2中退出整個腳本:

ls: cannot access file.that.doesnt.exist: No such file or directory 
+1

第二部分是誤導 - 如果'yourscript'設置'errexit',封裝代碼將確實在其內部的錯誤上放棄(用bash 4.2.x測試)。與常規使用shell if-then-else相比,這看起來可能與直覺相反,但如果您正在尋找不可靠的代碼,那麼期望您將它包裝在子外殼中似乎並不合理。 –

+1

@JosipRodin我看到bash 2和3中止了整個腳本,但在4.3.30(1) - 釋放它不能中止所描述的。有趣的是,知道這種行爲已經發生了很大的變化。 –

+0

好抓。我認爲目前的行爲與主要建議一致 - 使用子shell。例如,如果你這樣做:'set + e; (。yourscript);如果[$? -ne 0];然後回顯「初始化失敗」; fi' - 結果相當合理。 –

3

更改set -ereturn 0(或選擇您喜歡的整數而不是0)。你可以把它看作是一個函數來處理你的源文件。例如:

$ cat myreturn.sh 
#!/bin/bash 

let i=0 

while test "$i" -lt 10; do 

    echo "i $i" 
    if test "$i" -gt 5 ; then 
     return 5 
    fi 
    sleep 1 
    ((i+=1)) 

done 

return 4 

$ (. myreturn.sh) 
i 0 
i 1 
i 2 
i 3 
i 4 
i 5 
i 6 

$ echo $? 
5 
+0

爲什麼這個答覆不是第一個呢?非常感謝!! – eplaut

4

這是不可能的。然而,如果你願意,你可以選擇使用子shell:

(
    set -e 
    source another.sh 
) 

只有調用腳本的環境永遠不能被調用的腳本改變。

注意:使用換行符分隔兩個命令而不使用分號可能很重要。

2

嗯,這個問題不是很清楚重:

您可以設置:原作者攔截錯誤執行的腳本,但是,作爲一個切入點解決以下就足夠了之後想要什麼在ERR上捕獲並處理源腳本中的錯誤。以下是兩種情況:一種源腳本使用「set -e」,另一種腳本不使用「set -e」。

主腳本調用具有定義的「設置-e」和捕獲差錯的次級腳本:

[galaxy => ~]$ cat primary.sh 
#!/bin/sh 

set -e 
echo 'Primary script' 
trap 'echo "Got an error from the secondary script"' ERR 
source secondary.sh 
trap - ERR 
echo 'Primary script exiting' 
[galaxy => ~]$ cat secondary.sh 
#!/bin/sh 

echo 'Secondary script' 
set -e 
echo 'Secondary script generating an error' 
false 
echo 'Secondary script - should not be reached' 
[galaxy => ~]$ ./primary.sh 
Primary script 
Secondary script 
Secondary script generating an error 
Got an error from the secondary script 
[galaxy => ~]$ 

主腳本調用腳本次級沒有「設置-e」和捕獲錯誤:

[galaxy => ~]$ cat primary.sh 
#!/bin/sh 

set -e 
echo 'Primary script' 
trap 'echo "Got an error from the secondary script"' ERR 
source secondary.sh 
trap - ERR 
echo 'Primary script exiting' 
[galaxy => ~]$ cat secondary.sh 
#!/bin/sh 

echo 'Secondary script' 
echo 'Secondary script generating an error' 
false 
echo 'Secondary script - should not be reached if sourced by primary.sh' 
[galaxy => ~]$ ./primary.sh 
Primary script 
Secondary script 
Secondary script generating an error 
Got an error from the secondary script 
[galaxy => ~]$ 

作爲獎勵:在被執行的腳本攔截錯誤並繼續:

[galaxy => ~]$ cat primary.sh 
#!/bin/sh 

echo 'Primary script' 
i=0 
while [ $i = 0 ]; do 
    i=1 
    trap 'echo "Got an error from the secondary script"; break' ERR 
    source secondary.sh 
done 
trap - ERR 
echo 'Primary script exiting' 
[galaxy => ~]$ cat secondary.sh 
#!/bin/sh 

echo 'Secondary script' 
echo 'Secondary script generating an error' 
false 
echo 'Secondary script - should not be reached if sourced by primary.sh' 
[galaxy => ~]$ ./primary.sh 
Primary script 
Secondary script 
Secondary script generating an error 
Got an error from the secondary script 
Primary script exiting 
[galaxy => ~]$