Bash 为什么set-e;真与假&;假及&;真的不出口吗?

Bash 为什么set-e;真与假&;假及&;真的不出口吗?,bash,Bash,根据使用的set-e内置代码应该足以让bash脚本在出现第一个错误时退出。然而,以下脚本: #!/usr/bin/env bash set -e echo "a" echo "b" echo "about to fail" && /bin/false && echo "foo" echo "c" echo "d" 印刷品: $ ./foo.sh a b about to fail c d 删除回声“foo”会停止脚本;但是为什么呢?因为这个答案不够具体

根据使用的
set-e
内置代码应该足以让bash脚本在出现第一个错误时退出。然而,以下脚本:

#!/usr/bin/env bash

set -e

echo "a"
echo "b"
echo "about to fail" && /bin/false && echo "foo"
echo "c"
echo "d"
印刷品:

$ ./foo.sh 
a
b
about to fail
c
d

删除回声“foo”会停止脚本;但是为什么呢?

因为这个答案不够具体

它应该说(粗体文本是我添加的):

#任何失败的后续简单命令都将导致shell脚本立即退出

由于手册页的内容如下:

-e      Exit  immediately if a simple command (see SHELL GRAMMAR
        above) exits with a non-zero status.  The shell does not
        exit  if  the  command that fails is part of the command
        list immediately following a  while  or  until  keyword,
        part  of the test in an if statement, part of a && or ││
        list, or if the command’s return value is being inverted
        via  !.   A  trap on ERR, if set, is executed before the
        shell exits.
SHELL GRAMMAR
   Simple Commands
       A simple command is a sequence of optional  variable  assignments  fol-
       lowed  by  blank-separated  words and redirections, and terminated by a
       control operator.  The first word specifies the command to be executed,
       and  is  passed  as  argument  zero.  The remaining words are passed as
       arguments to the invoked command.

       The return value of a simple command is its exit status,  or  128+n  if
       the command is terminated by signal n.
而SHELL语法则展开如下:

-e      Exit  immediately if a simple command (see SHELL GRAMMAR
        above) exits with a non-zero status.  The shell does not
        exit  if  the  command that fails is part of the command
        list immediately following a  while  or  until  keyword,
        part  of the test in an if statement, part of a && or ││
        list, or if the command’s return value is being inverted
        via  !.   A  trap on ERR, if set, is executed before the
        shell exits.
SHELL GRAMMAR
   Simple Commands
       A simple command is a sequence of optional  variable  assignments  fol-
       lowed  by  blank-separated  words and redirections, and terminated by a
       control operator.  The first word specifies the command to be executed,
       and  is  passed  as  argument  zero.  The remaining words are passed as
       arguments to the invoked command.

       The return value of a simple command is its exit status,  or  128+n  if
       the command is terminated by signal n.

为了简化EtanReisner的详细回答,
set-e
只存在“未捕获”错误。就你而言:

echo "about to fail" && /bin/false && echo "foo"
失败代码
/bin/false
,后面跟着测试退出代码的
&&
。由于
&&
测试退出代码,因此假设程序员知道自己在做什么,并预期此命令可能失败。因此,脚本不会退出

相比之下,请考虑:

echo "about to fail" && /bin/false
程序不会在退出代码
/bin/false
上进行测试或分支。因此,当
/bin/false
失败时,
set-e
将导致脚本退出

/bin/false
失败时退出的备选方案 考虑:

set -e
echo "about to fail" && /bin/false ; echo "foo"

如果
/bin/false
失败,此版本将退出。与使用
&&
的情况一样,最后的语句
回显“foo”因此,只有在
/bin/false
成功的情况下才会执行

我遇到Bash脚本的
set-e
,但在理解
&
&
列表中最后一个
&
|
之后的命令求值时遇到了问题。我从《关于
set-e
》中知道以下引用:

如果失败的命令是()的一部分,则shell不会退出 在
&&
| |
列表中执行的任何命令,命令除外 在最后的
&&
|
之后(…)

为了测试这一点,我编写了一个小Bash脚本:

#!/bin/bash

bash -c "set -e ; true           ; echo -n A"
bash -c "set -e ; false          ; echo -n B"
bash -c "set -e ; true  && true  ; echo -n C"
bash -c "set -e ; true  && false ; echo -n D"
bash -c "set -e ; false && true  ; echo -n E"
bash -c "set -e ; false && false ; echo -n F"
bash -c "set -e ; true  || true  ; echo -n G"
bash -c "set -e ; true  || false ; echo -n H"
bash -c "set -e ; false || true  ; echo -n I"
bash -c "set -e ; false || false ; echo -n J"

echo ""
它打印:

ACEFGHI

关于A:

true
没有非零状态。因此,shell不会退出

关于B:

false
的状态为非零,不属于
&
|
列表的一部分。因此,shell退出

关于C:

这是一个
&
|
列表。我们必须查看最后一个
&&
|
后面的命令。该命令为
true
,没有非零状态。因此,不管命令是否被计算,shell都不会以任何方式退出

关于D:

这是一个
&
|
列表。我们必须查看最后一个
&&
|
后面的命令。这一次,命令为
false
,其状态为非零。因此,我们必须检查是否正在评估
false
——这确实是事实,因为
&&
遵循
true
。因此,shell退出

关于E:

C的推理相同:
true
是最后一个
&
|
后面的命令。因此,shell不会退出

关于F:

类似于D:这是一个
&
|
列表。我们必须查看最后一个
&&
|
后面的命令。同样,该命令为
false
,其状态为非零。但是这次没关系,因为第一个命令也是
false
。因为它是一个
&
列表,所以第二个
false
将不会被计算。因此,shell不会退出

关于G:

CE的推理相同:
true
是最后一个
&
|
后面的命令。因此,shell不会退出

关于H:

这是一个
&
|
列表。我们必须查看最后一个
&&
|
后面的命令。此命令为
false
,其状态为非零,但不会对其求值,因为
|
前面有
true
。因此,shell不会退出

关于我:

CEG的推理相同:
true
是最后一个
&
|
后面的命令。因此,shell不会退出

关于J:

这是一个
&
|
列表。我们必须查看最后一个
&&
|
后面的命令。此命令为
false
,状态为非零。由于
|
前面有
false
,因此将计算第二个
false
。因此,shell不会退出



您应该能够将这些测试用例应用到您的用例中:
true&&false&&true
。由于最后一个
&&
|
后面的命令是
true
,没有非零状态,因此无论
&&
|
前面的命令是什么,shell都不会以任何方式退出。

好吧,想玩“手册页律师”,显然,如果失败的命令是
&&
列表上的最后一个命令,则shell确实会退出,因此,如果命令[…]是&&[…]列表的一部分
,则读取“
的部分不会退出”correct@MarcusJuniusBrutus
-e
的文档明确介绍了该细节。“如果失败的命令是&&or的一部分,则shell不会退出││ 列出“尽管如此