2010-09-29 151 views
138

我是shell腳本的noob。如果命令失敗,我想打印一條消息並退出我的腳本。我試過了:如何在命令失敗時退出?

my_command && (echo 'my_command failed; exit) 

但它不起作用。它會繼續執行腳本中此行後面的指令。我使用Ubuntu和bash。

+3

您是否打算將未封閉的引用作爲會導致失敗/退出的語法錯誤?如果沒有,你應該關閉你的例子中的報價。 – hobs 2015-12-29 18:02:02

回答

268

嘗試:

my_command || { echo 'my_command failed' ; exit 1; } 

四改:

  • 變化&&||
  • 使用{ }代替()
  • 介紹;exit
  • 空間{之後和之前}

既然你要打印的消息並退出,只有當命令失敗(退出時非零值),你需要一個||不是&&

cmd1 && cmd2 

將運行時cmd2cmd1成功(退出值0)。凡爲

cmd1 || cmd2 

將運行cmd2cmd1失敗(退出值不爲零)。

使用()使它們內部的命令在子shell運行,並調用exit從那裏使你退出子殼,而不是原來的殼,從而繼續執行在原來的殼。

爲了克服這種使用{ }

bash所需要的最後兩個變化。

+3

它看起來似乎是「顛倒過來」。如果函數「成功」,則返回0,如果「失敗」,則返回非零值,因此&&可能需要在前半部分返回非零值時計算。 這並不意味着上面的答案是不正確的 - 不,它是正確的。&&和||在腳本中基於成功而不是返回值。 – CashCow 2012-07-20 10:43:50

+6

看起來相反,但讀出來,它是有道理的:「做這個命令(成功)」或「打印此錯誤並退出」 – simpleuser 2014-03-14 22:18:36

+2

它的邏輯是該語言使用短路評估(SCE)。對於SCE,f表達式的形式爲「p OR q」,並且p被評估爲真,那麼沒有理由甚至不需要q。如果表達式的形式爲「p AND q」,並且p被評估爲false,則沒有理由查看q。其原因有兩方面:1)速度更快,原因很明顯,2)避免了某些類型的錯誤(例如:「如果x!= 0 AND 10/x> 5」在沒有SCE時會崩潰)。像這樣在命令行中使用它的能力是一個令人愉快的副作用。 – user2635263 2015-07-11 00:01:34

10

提供my_command是規範設計的,成功返回0,則&&正好與你想要的相反。你想要||

另外請注意,(似乎不適合我在bash中,但我不能嘗試從我的位置。告訴我。

my_command || { 
    echo 'my_command failed' ; 
    exit 1; 
} 
+0

IIRC,在{} – 2010-09-29 14:35:42

+7

@Alex中的每一行後面都需要分號:如果它們在單獨的行上,則不需要分號。 – 2010-09-29 15:47:28

53

另請注意,每個命令的退出狀態都存儲在shell變量$?中,您可以在運行該命令後立即檢查該變量。非零狀態表示失敗:

my_command 
if [ $? -eq 0 ] 
then 
    echo "it worked" 
else 
    echo "it failed" 
fi 
+8

這可以替換爲my_command,這裏不需要使用test命令。 – 2010-09-29 14:53:51

+5

+1,因爲我認爲你不應該因爲列出這個替代品而受到懲罰 - 它應該放在桌面上 - 雖然它有點難看,而且根據我的經驗,在其中間運行另一個命令時不會注意到測試的本質(也許我很容易只是愚蠢的)。 – 2010-09-30 08:34:32

+1

@BartSas如果命令很長,最好把它放在自己的路線上。它使腳本更具可讀性。 – Michael 2012-08-13 19:45:28

94

其他的答案已經涵蓋了直接的問題很好,但你也可能有興趣使用set -e。因此,任何失敗的命令(例如if測試以外的特定上下文)都將導致腳本中止。對於某些腳本,它非常有用。

12

我砍死了下面的語句:

echo "Generating from IDL..." 
idlj -fclient -td java/src echo.idl 
if [ $? -ne 0 ]; then { echo "Failed, aborting." ; exit 1; } fi 

echo "Compiling classes..." 
javac *java 
if [ $? -ne 0 ]; then { echo "Failed, aborting." ; exit 1; } fi 

echo "Done." 

前面加上一個資料回聲每個命令,並按照每個命令與相同
if [ $? -ne 0 ];...線。 (當然,你可以,如果你想要編輯的錯誤消息。)

+0

這可以被定義爲一個函數,從而重用它。 – 2017-03-15 12:46:34

47

如果你想在你的腳本中的所有命令該行爲,只需添加

set -e 
    set -o pipefail 

在腳本的開始。這一對選項告訴bash解釋器在一個命令返回非零退出代碼時退出。

雖然這不允許您輸出退出消息。

+6

您可以使用'trap' bash內置命令在退出時運行命令。 – 2014-04-12 18:07:53

+0

這是X-Y問題的答案。 – jwg 2015-11-06 16:14:47

+3

可能有趣的是解釋哪些命令獨立執行而不是配對。特別是因爲'set -o pipefail'可能不是所需的行爲。仍然感謝您指出! – 2017-01-26 10:49:29

0

您也可以使用,如果你想保留退出錯誤狀態,並且有一個可讀的文件,每行一個命令:

my_command1 || exit $? 
my_command2 || exit $? 

但是,這不會打印任何其他錯誤消息。但是在某些情況下,無論如何,錯誤將由失敗的命令打印。

0

trap shell內建允許捕獲信號以及其他有用的條件,包括失敗的命令執行(即非零返回狀態)。所以如果你不想明確地測試每一個命令的返回狀態,你可以說trap "your shell code" ERR,並且任何時候一個命令返回一個非零狀態都會執行shell代碼。例如:

trap "echo script failed; exit 1" ERR

注意的是,與捕獲失敗的命令的其它情況下,管道,需要特殊處理;以上將不會趕上false | true

相關問題