错误退出脚本


141

我正在构建具有以下if功能的Shell脚本:

if jarsigner -verbose -keystore $keyst -keystore $pass $jar_file $kalias
then
    echo $jar_file signed sucessfully
else
    echo ERROR: Failed to sign $jar_file. Please recheck the variables
fi

...

我希望在显示错误消息后完成脚本的执行。我该怎么做?

Answers:


137

您在找exit吗?

这是周围最好的bash指南。 http://tldp.org/LDP/abs/html/

在上下文中:

if jarsigner -verbose -keystore $keyst -keystore $pass $jar_file $kalias
then
    echo $jar_file signed sucessfully
else
    echo ERROR: Failed to sign $jar_file. Please recheck the variables 1>&2
    exit 1 # terminate and indicate error
fi

...

5
如果您喜欢ABS,那么您会喜欢BashGuideBashFAQBashPitfalls
暂停,直到另行通知。

那些Bash链接真棒!BashFAQ可以更好地定位为BashRecipes。
皮特·阿尔文,

337

如果放入set -e脚本,则脚本中的任何命令失败都会终止脚本(即,任何命令返回非零状态)。这不允许您编写自己的消息,但是失败命令自己的消息通常就足够了。

这种方法的优点是它是自动的:您不会冒忘记处理错误情况的风险。

命令其地位是通过条件测试(如if&&||)不终止脚本(否则有条件的将是毫无意义)。对于偶尔的命令来说,失败无关紧要的习惯用法是command-that-may-fail || true。您也可以使用set -e关闭部分脚本set +e


3
根据mywiki.wooledge.org/BashFAQ/105,此功能在确定哪些命令的错误代码会导致自动退出方面具有晦涩难懂的历史。此外,“由于Bash试图跟踪该'功能'的极滑POSIX定义,因此规则从一种Bash版本更改为另一种版本”。我同意@Dennis Williamson和stackoverflow.com/questions/19622198/…的公认答案-使用陷阱'error_handler'ERR。即使是陷阱!
Bondolin 2015年

3
通常将-x标志与标志一起使用-e就足以说明程序退出的位置。这意味着脚本的用户也是开发人员。
Alex

很好,但是我认为OP需要从自定义异常中退出脚本。
vdegenne

42

如果您希望能够处理错误而不是盲目退出,而不是使用 set -e,请trapERR伪信号上使用a 。

#!/bin/bash
f () {
    errorCode=$? # save the exit code as the first thing done in the trap function
    echo "error $errorCode"
    echo "the command executing at the time of the error was"
    echo "$BASH_COMMAND"
    echo "on line ${BASH_LINENO[0]}"
    # do some error handling, cleanup, logging, notification
    # $BASH_COMMAND contains the command that was being executed at the time of the trap
    # ${BASH_LINENO[0]} contains the line number in the script of that command
    # exit the script or return to try again, etc.
    exit $errorCode  # or use some other value or do return instead
}
trap f ERR
# do some stuff
false # returns 1 so it triggers the trap
# maybe do some other stuff

可以将其他陷阱设置为处理其他信号,包括通常的Unix信号以及其他Bash伪信号RETURNDEBUG


8

这是这样做的方法:

#!/bin/sh

abort()
{
    echo >&2 '
***************
*** ABORTED ***
***************
'
    echo "An error occurred. Exiting..." >&2
    exit 1
}

trap 'abort' 0

set -e

# Add your script below....
# If an error occurs, the abort() function will be called.
#----------------------------------------------------------
# ===> Your script goes here
# Done!
trap : 0

echo >&2 '
************
*** DONE *** 
************
'

为什么将完成消息发送到stderr?
MattBianco 2014年

1
这是一种常见的做法,因此您可以将脚本输出通过管道传输到stdout,这样另一个进程就可以将其输出,而无需在中间插入信息消息。
supercobra 2014年

2
将stderr上的任何内容视为问题的指示可能是同等普遍的做法。
MattBianco 2014年

1
过去,“ set -e”一直为我工作,但是今晚我遇到了一个在Alpine Linux Docker映像中没有任何作用的情况。非常感激。
synthesizerpatel

@supercobra常见做法?哪里?
托尔比约恩Ravn的安徒生

-8

exit 1是你所需要的全部。该1是一个返回代码,所以你可以改变它,如果你想,说,1是指成功运行,并-1意味着故障或类似的东西。


13
在Unix中,成功始终为0。使用test&&或可能会有所帮助||
mouviciel 2010年

5
进一步阐述mouviciel的评论:在shell脚本中,0始终表示成功,而1到255则表示失败。-1超出范围(并且通常具有与255相同的效果,因此失败如1)。
吉尔(Gilles)“所以,别再邪恶了”

@ mouviciel,@ Gilles:感谢您提供更多信息。自从我处理bash已经有一段时间了。
DGH 2010年

这是返回码用法的不好例子,否则将是一个很好的答案。
布拉德·科赫

1
除了错误地建议1成功外,-1也是不可能的(退出代码未签名)。
Tripleee '16
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.