关于linux:如果命令失败,如何退出?

How to exit if a command failed?

我对shell脚本编写很在行。如果命令失败,我想打印一条消息并退出脚本。我试过了:

1
my_command && (echo 'my_command failed; exit)

但它不起作用。它一直在执行脚本中这一行后面的指令。我用的是Ubuntu和Bash。


尝试:

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

四个变化:

  • &&改为||
  • { }代替( )
  • exit之后引入;
  • {后和}前的空格

由于您只想打印消息并在命令失败时退出(以非零值退出),因此需要一个||,而不是&&

1
cmd1 && cmd2

cmd1成功(退出值0时,将运行cmd2。在哪里

1
cmd1 || cmd2

cmd1失败(退出值非零)时,将运行cmd2

使用( )使其内部的命令在子shell中运行,并从中调用exit会导致您退出子shell而不是原来的shell,因此在原来的shell中继续执行。

为了克服这种情况,使用{ }

最后两个更改是bash所必需的。


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


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

1
2
  set -e
  set -o pipefail

在脚本的开头。这对选项告诉bash解释器,每当命令返回非零退出代码时,都要退出。

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


注意,每个命令的退出状态都存储在shell变量$?,可以在运行命令后立即检查。非零状态表示故障:

1
2
3
4
5
6
7
my_command
if [ $? -eq 0 ]
then
    echo"it worked"
else
    echo"it failed"
fi


我已经把下面的成语拼凑了一下:

1
2
3
4
5
6
7
8
9
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 ];...线。(当然,如果需要,可以编辑该错误消息。)


如果my_command是规范设计的,即成功时返回0,那么&&与您想要的正好相反。你要的是||

同样要注意的是,在巴什,以东十一〔三〕在我看来是不对的,但我不能从我所在的地方去尝试。告诉我。

1
2
3
4
my_command || {
    echo 'my_command failed' ;
    exit 1;
}


trapshell内置允许捕获信号和其他有用条件,包括命令执行失败(即非零返回状态)。因此,如果您不想显式测试每个命令的返回状态,您可以说trap"your shell code" ERR,并且在命令返回非零状态时,shell代码将被执行。例如:

trap"echo script failed; exit 1" ERR

注意,与其他捕获失败命令的情况一样,管道需要特殊处理;上述情况不会捕获false | true


如果要保留退出错误状态,并且每行有一个命令的可读文件,也可以使用:

1
2
my_command1 || exit $?
my_command2 || exit $?

但是,这不会打印任何其他错误消息。但在某些情况下,错误将由失败的命令打印出来。


以下函数仅在命令失败时回显错误:

1
2
3
4
5
6
7
8
9
10
silently () {
    label="${1}"
    command="${2}"
    error=$(eval"${command}" 2>&1 >"/dev/null")

    if [ ${?} -ne 0 ]; then
        echo"${label}: ${error}">&2
        exit 1
    fi
}