我一直在写一些shell脚本,如果有能力停止所述shell脚本的执行,如果任何命令失败,我会发现它很有用。请看下面的例子:

#!/bin/bash

cd some_dir

./configure --some-flags

make

make install

因此,在这种情况下,如果脚本不能更改到指定的目录,那么如果失败,它肯定不想在之后执行./configure。

现在我很清楚,我可以对每个命令进行if检查(我认为这是一个无望的解决方案),但是是否存在一个全局设置,以便在其中一个命令失败时使脚本退出?


当前回答

我认为你要找的是trap命令:

trap command signal [signal ...]

欲了解更多信息,请参阅本页。

另一种选择是在脚本顶部使用set -e命令——如果任何程序/命令返回非真值,它将使脚本退出。

其他回答

另一种适合第一行的可接受的答案:

#!/bin/bash -e

cd some_dir  

./configure --some-flags  

make  

make install

一个成语是:

cd some_dir && ./configure --some-flags && make && make install

我知道这可能会很长,但对于较大的脚本,您可以将其分解为逻辑函数。

现有的答案中有一点没有说明如何继承错误陷阱。bash shell为使用set提供了这样一个选项

- e 如果设置了,ERR上的任何trap都将由shell函数、命令替换和在子shell环境中执行的命令继承。在这种情况下,ERR陷阱通常不会被继承。


Adam Rosenfield建议使用set -e的答案在某些情况下是正确的,但它也有自己的潜在缺陷。见GreyCat的BashFAQ - 105 -为什么不设置-e(或设置-o errexit,或陷阱ERR)做我所期望的?

根据手册,set -e退出

如果一个简单的命令以非零状态出现。如果失败的命令是紧跟着while或until关键字的命令列表的一部分,if语句中的测试的一部分,&&或||列表的一部分,除了最后一个&&或||后面的命令,管道中的任何命令,或者如果命令的返回值被颠倒!”,shell不会退出。

这意味着,set -e在以下简单情况下不起作用(详细解释可以在wiki上找到)

Using the arithmetic operator let or $((..)) ( bash 4.1 onwards) to increment a variable value as #!/usr/bin/env bash set -e i=0 let i++ # or ((i++)) on bash 4.1 or later echo "i is $i" If the offending command is not part of the last command executed via && or ||. For e.g. the below trap wouldn't fire when its expected to #!/usr/bin/env bash set -e test -d nosuchdir && echo no dir echo survived When used incorrectly in an if statement as, the exit code of the if statement is the exit code of the last executed command. In the example below the last executed command was echo which wouldn't fire the trap, even though the test -d failed #!/usr/bin/env bash set -e f() { if test -d nosuchdir; then echo no dir; fi; } f echo survived When used with command-substitution, they are ignored, unless inherit_errexit is set with bash 4.4 #!/usr/bin/env bash set -e foo=$(expr 1-1; true) echo survived when you use commands that look like assignments but aren't, such as export, declare, typeset or local. Here the function call to f will not exit as local has swept the error code that was set previously. set -e f() { local var=$(somecommand that fails); } g() { local var; var=$(somecommand that fails); } When used in a pipeline, and the offending command is not part of the last command. For e.g. the below command would still go through. One options is to enable pipefail by returning the exit code of the first failed process: set -e somecommand that fails | cat - echo survived

理想的建议是不使用set -e,而是实现自己的错误检查版本。关于在Bash脚本中引发错误的回答之一上实现自定义错误处理的更多信息

将它与pipefail结合使用。

set -e
set -o pipefail

-e (errexit):当命令以非零状态退出时,在出现第一个错误时终止脚本(until或while循环、if-tests和列表构造除外)

-o pipefail:使管道返回非零返回值的管道中最后一条命令的退出状态。

33章。选项

我认为你要找的是trap命令:

trap command signal [signal ...]

欲了解更多信息,请参阅本页。

另一种选择是在脚本顶部使用set -e命令——如果任何程序/命令返回非真值,它将使脚本退出。