我认为set -e
对子 shell 的影响与对顶级 shell 的影响相同。显然,事实并非如此。这:
(
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
印刷
false2
false3
false5
这是在哪里记录的?我是否可以让子 shell 因错误而终止,而无需连接所有命令&&
(或在每个命令后不执行操作|| exit $?
)?
编辑:
我的具体用例是这样的:
set -e
# ...
status=0
( false; true ) || status=$?
report_code $status
return $status
子 shell 的内容是我的实际代码。这样做的问题是它总是将状态设置为 0,并且由于外部设置 -e而替换||
为会导致不必要的错误退出。;
我用以下方法解决了它:
set -e
# ...
set +e
( false; true ); status=$?
set -e
report_code $status
return $status
我希望我不必这样做,但似乎所有常见的 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
输出:
FORK'D:
dash 0
bash 0
ksh 0
zsh 0
EXEC'D:
dash 1
bash 1
ksh 1
zsh 1
答案1
观察:
$ ( set -e; false ; true ) || echo false1
$ ( set -e; false ; true ) ; echo code=$?
code=1
还:
$ ( set -e; false ; true; echo inside=$? ) || echo false1
inside=0
显然,当子 shell 后跟||
,时set -e
,不会导致子 shell 在到达false
命令时退出。相反,子 shell 继续并执行true
(and echo inside=$?
)。
它的理念set -e
通常是,它仅在未捕获的错误时才存在。在这里,子 shell 外部的存在||
似乎告诉 shell 子 shell 内部的错误已被“捕获”,因此set -e
不会导致 后退出false
。
set -e
有许多令人惊讶的行为。看“为什么 set -e 没有达到我的预期?”
文档
上述行为在以下文档中有所暗示man bash
:
-e
如果管道(可能由单个简单命令组成)、列表或复合命令(请参阅上面的 SHELL GRAMMAR)以非零状态退出,则立即退出。 如果失败的命令是 shell,则 shell 不会退出命令列表的一部分紧跟在 while 或 Until 关键字之后,测试的一部分在 if 或 elif 保留字之后,在 && 或 || 中执行的任何命令的一部分列表除了最后一个 && 或 || 后面的命令之外,管道中除最后一个命令之外的任何命令,或者命令的返回值与 ! 反转。如果子 shell 之外的复合命令由于在忽略 -e 时命令失败而返回非零状态,则 shell 不会退出。如果设置了 ERR 陷阱,则会在 shell 退出之前执行。此选项分别适用于 shell 环境和每个子 shell 环境(请参阅上面的命令执行环境),并且可能会导致子 shell 在执行子 shell 中的所有命令之前退出。 [强调。]