我认为set -e
对子外壳和顶级外壳有相同的影响。显然,事实并非如此。这个:
(
set -e
false
true
) || echo false1
bash -ec '
set -e
false
true
' || echo false2
bash <<EOF || echo false3
set -e
false
true
EOF
bash <<EOF || echo false4
false
true
EOF
bash <<EOF || echo false5
false &&
true
EOF
Run Code Online (Sandbox Code Playgroud)
印刷
false2
false3
false5
Run Code Online (Sandbox Code Playgroud)
这是在哪里记录的?我可以让子外壳程序在错误时终止,而不用&&
(或|| exit $?
在每个命令之后不执行)连接所有命令吗?
编辑:
我的特定用例是这样的:
set -e
# ...
status=0
( false; true ) || status=$?
report_code $status
return $status
Run Code Online (Sandbox Code Playgroud)
子shell的内容是我的实际代码。这样做的问题是它总是将状态设置为 0,并且由于外部设置 -e而替换||
为;
会导致不必要的错误退出。
我用以下方法解决了它:
set -e
# ...
set +e
( false; true ); status=$?
set -e
report_code $status
return $status
Run Code Online (Sandbox Code Playgroud)
我希望我不必这样做,但似乎所有常见的 shell 都显示了这个 execed-subshell 与 just-forked-subshell 二分法:
#!/bin/sh
echo FORK\'D:
export SH
for SH in dash bash ksh zsh; do
$SH -c 'st=0; ( set -e; false; true ) || st=$?; printf "%s\t%s\n" $SH $st; '
done
echo EXEC\'D:
for SH in dash bash ksh zsh; do
$SH -c 'st=0; '$SH' -c " set -e; false; true " || st=$?; printf "%s\t%s\n" $SH $st; '
done
Run Code Online (Sandbox Code Playgroud)
输出:
FORK'D:
dash 0
bash 0
ksh 0
zsh 0
EXEC'D:
dash 1
bash 1
ksh 1
zsh 1
Run Code Online (Sandbox Code Playgroud)
Joh*_*024 17
观察:
$ ( set -e; false ; true ) || echo false1
$ ( set -e; false ; true ) ; echo code=$?
code=1
Run Code Online (Sandbox Code Playgroud)
还:
$ ( set -e; false ; true; echo inside=$? ) || echo false1
inside=0
Run Code Online (Sandbox Code Playgroud)
显然,当子外壳后跟 a 时||
,set -e
不会导致子外壳在到达false
命令时退出。相反,子shell 继续并执行true
(和echo inside=$?
)。
的哲学set -e
通常是它仅在未捕获的错误时退出。在这里,||
子外壳外部的存在似乎告诉外壳子外壳内部的错误被“捕获”,因此set -e
不会在false
.
set -e
有许多令人惊讶的行为。请参阅“为什么 set -e 不符合我的预期?”
上面的行为在以下文档中有所暗示man bash
:
-e
如果管道(可能由单个简单命令组成)、列表或复合命令(参见上面的 SHELL GRAMMAR)以非零状态退出,则立即退出。 如果失败的命令是紧跟在 while 或 until 关键字之后的命令列表的一部分、在 if 或 elif 保留字之后的测试的一部分、在 && 或 || 中执行的任何命令的一部分,则 shell 不会退出 列表除了最后一个 && 或 || 之后的命令,管道中除最后一个之外的任何命令,或者如果命令的返回值正在用 ! 反转。如果除子 shell 之外的复合命令由于命令在 -e 被忽略时失败而返回非零状态,则 shell 不会退出。如果设置了 ERR 上的陷阱,则会在 shell 退出之前执行。此选项分别适用于 shell 环境和每个子 shell 环境(参见上面的命令执行环境),并且可能导致子 shell 在执行子 shell 中的所有命令之前退出。[强调。]