我在编写shell脚本方面是个新手。如果命令失败,我想打印一条消息并退出脚本。我试过了:

my_command && (echo 'my_command failed; exit)

但这并不奏效。它继续执行脚本中这一行之后的指令。我使用Ubuntu和bash。


当前回答

如果您希望脚本中的所有命令都具有这种行为,只需添加

set -e 
set -o pipefail

在脚本的开头。这对选项告诉bash解释器,当命令返回非零退出码时,就退出。(更多关于为什么需要pipefail的详细信息,请参见http://petereisentraut.blogspot.com/2010/11/pipefail.html)

但是,这并不允许您打印退出消息。

其他回答

如果您希望脚本中的所有命令都具有这种行为,只需添加

set -e 
set -o pipefail

在脚本的开头。这对选项告诉bash解释器,当命令返回非零退出码时,就退出。(更多关于为什么需要pipefail的详细信息,请参见http://petereisentraut.blogspot.com/2010/11/pipefail.html)

但是,这并不允许您打印退出消息。

直接使用exit可能有点棘手,因为脚本可能来自其他地方(例如,从终端)。我更喜欢使用带有set -e的subshell(加上错误应该进入cerr,而不是cout):

set -e
ERRCODE=0
my_command || ERRCODE=$?
test $ERRCODE == 0 ||
    (>&2 echo "My command failed ($ERRCODE)"; exit $ERRCODE)

其他答案已经很好地涵盖了直接问题,但您可能也对使用set -e感兴趣。因此,任何失败的命令(在特定上下文之外,如if测试)都将导致脚本中止。对于某些脚本,它非常有用。

如果my_command是规范设计的,ie成功时返回0,那么&&与你想要的完全相反。你要||。

还要注意,(在bash中对我来说似乎不正确,但我不能从我所在的位置尝试。告诉我。

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

我把下面这个习语拼凑起来了:

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."

在每个命令的前面加上一个有信息的回显,并在每个命令后面加上同样的回显 如果[$?-ne 0];…线。(当然,如果您愿意,您可以编辑该错误消息。)