-e
设置选项时,我对 bash (和 dash)的行为感到困惑。
简单的例子:
#!/bin/bash -e
func() {
false && true
}
false && true
echo "1"
func
echo "2"
输出:
1
预期输出:
1
2
虽然第一次出现按预期工作,但第二次出现(在函数内部)会导致立即退出。我搜索了文档,但无法找到对这种不同行为的解释。这背后有什么理由吗,或者这是一个错误?我在 bash 和 dash 中测试了这一点,结果相同。
根据 bash 手册页:
-e
如果管道(可能由单个简单命令组成)、列表或复合命令(请参阅上面的 SHELL GRAMMAR)以非零状态退出,请立即退出。如果失败的命令是紧跟在while
或关键字之后的命令列表的一部分、是在或保留字until
之后的测试的一部分、是在或列表中执行的任何命令的一部分(最后一个或之后的命令除外),则shell 不会退出。管道中的最后一个命令,或者命令的返回值与.如果子 shell 之外的复合命令由于命令在被忽略时失败而返回非零状态,则 shell 不会退出。如果设置了上的陷阱,则会在 shell 退出之前执行。此选项分别适用于 shell 环境和每个子 shell 环境(请参阅上面的命令执行环境),并且可能会导致子 shell 在执行子 shell 中的所有命令之前退出。if
elif
&&
||
&&
||
!
-e
ERR
如果复合命令或 shell 函数在被忽略的上下文中执行
-e
,则在复合命令或函数体内执行的任何命令都不会受到该-e
设置的影响,即使-e
已设置并且命令返回失败状态。如果复合命令或 shell 函数在被忽略的-e
上下文中执行时设置-e
,则在复合命令或包含函数调用的命令完成之前,该设置不会产生任何效果。
答案1
该脚本在从 返回时终止func
,因为其退出状态不为零。该脚本并未在 内终止func
。
该false && true
列表不受 的影响-e
,并且脚本不会从中终止,不在脚本的主要部分中,也不在函数中。
然而,false
函数中的 将该函数的退出状态设置为非零,因此当函数返回时,shell 终止。
您的脚本可以简化为
#!/bin/bash -e
false && true
echo "1"
false
echo "2"
您可能还想测试从函数返回零,以说服自己false && true
函数中的列表不会终止脚本:
#!/bin/bash -e
func() {
false && true
return 0
}
false && true
echo "1"
func
echo "2"
运行此输出
1
2
答案2
不直接相关,因为您没有询问trap
s,但是......
ERR 陷阱和 set -E 与 set -e
请注意,set -E
不包括set -e
.鉴于此脚本在函数中存在错误:
$ cat trap_test.sh
#!/usr/bin/env bash
trap 'echo "Error on line $LINENO. Exit code: $?" >&2' ERR
myfunc() {
noSuchCommand
echo OK
}
myfunc
那么我们可以检查 -E 和 -e 的组合
- 均未指定:无陷阱,无提前退出
$ bash trap_test.sh; echo "exit status: $?" trap_test.sh: line 6: noSuchCommand: command not found OK exit status: 0
- -e:提前退出,函数中不存在陷阱
$ bash -e trap_test.sh; echo "exit status: $?" trap_test.sh: line 6: noSuchCommand: command not found exit status: 127
- -E,由于函数中的错误而引发的陷阱
$ bash -E trap_test.sh; echo "exit status: $?" trap_test.sh: line 6: noSuchCommand: command not found Error on line 6. Exit code: 127 OK exit status: 0
- 提前退出和陷阱/
$ bash -eE trap_test.sh; echo "exit status: $?" trap_test.sh: line 6: noSuchCommand: command not found Error on line 6. Exit code: 127 exit status: 127