bash set -e 和简短的测试
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6930295/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
set -e and short tests
提问by Teresa e Junior
When I was new to shell scripting, I used a lot of short tests instead of ifstatements, like false && true.
当我刚接触 shell 脚本时,我使用了很多简短的测试而不是if语句,比如false && true.
Then later I learned using set -e, and found my scripts were dying for some reason, and they would work if I replaced the short tests with full ifstatements. Now, the time has gone, and I still use full ifstatements only.
后来我学会了使用set -e,发现我的脚本由于某种原因正在消失,如果我用完整的if语句替换简短的测试,它们就会起作用。现在,时间已经过去了,我仍然if只使用完整的语句。
The most interesting is that if I open an interactive shell and do the following:
最有趣的是,如果我打开一个交互式 shell 并执行以下操作:
set -e
false && true
echo $?
it returns 1 but the shell doesn't die!
它返回 1 但外壳没有死!
I see that I have been wasting too many lines of code. Anyone could explain to me how can I use set -ewith short tests safely, eg. without the script dying?
我看到我一直在浪费太多的代码行。任何人都可以向我解释如何set -e安全地使用短期测试,例如。没有脚本死?
采纳答案by Teresa e Junior
Regarding my problem of the script unexpectedly dying, it is due to running those short tests in a subshell, or from a function, and said function returns a value different than zero:
关于我的脚本意外死亡的问题,这是由于在子 shell 中或从函数中运行这些简短的测试,并且所述函数返回一个不同于零的值:
Original example:
原始示例:
$ set -e
$ false && true
$ echo $?
1
Using a subshell or function:
使用子shell或函数:
$ set -e
$ (false && true)
<script died>
$ set -e
$ variable=$(false && true)
<script died>
$ set -e
$ foo()(false && true)
$ foo
<script died>
$ set -e
$ foo(){ false && true; }
$ foo
<script died>
Possible solutions:
可能的解决方案:
$ set -e
$ (false && true ||:)
$ (false && true) ||:
$ (if false; then true; fi)
回答by Danilo Piazzalunga
The Single UNIX Specificationdescribes the effect of set -eas:
的单一UNIX规范描述的效果set -e为:
When this option is on, if a simple command fails for any of the reasons listed in Consequences of Shell Errors or returns an exit status value >0, and is not part of the compound list following a while, until, or if keyword, and is not a part of an AND or OR list, and is not a pipeline preceded by the ! reserved word, then the shell shall immediately exit.
当此选项打开时,如果简单命令因外壳错误的后果中列出的任何原因而失败或返回退出状态值 >0,并且在 while、until 或 if 关键字之后不属于复合列表的一部分,并且不是 AND 或 OR 列表的一部分,也不是以 ! 保留字,则外壳应立即退出。
As you see, a failing command in an AND list will not make the shell exit.
如您所见,AND 列表中的失败命令不会使 shell 退出。
Using set -e
使用 set -e
Starting shell scripts with set -eis considered a best practice, since it is usually safer to abort the script if some error occurs. If a command may fail harmlessly, I usually append || trueto it.
使用 启动 shell 脚本set -e被认为是最佳实践,因为如果发生某些错误,中止脚本通常更安全。如果命令可能无害地失败,我通常会附加|| true到它。
Here is a simple example:
这是一个简单的例子:
#!/bin/sh
set -e
# [...]
# remove old backup files; do not fail if none exist
rm *~ *.bak || true
回答by Pawe? Nadolski
You need to end each command which may fail with ||and a command or command list evaluating to 0. Using ||will trigger your command if the expression before operator does not evaluate to 0. Your command needs to evaluate to 0 to not kill the shell.
您需要结束每个可能失败||的命令,并且命令或命令列表的计算结果为 0。||如果运算符之前的表达式不计算为 0,Using将触发您的命令。您的命令需要计算为 0 才能不终止 shell。
Example:
例子:
set -e
false || true # silently ignore error
false || echo "Command failed, but exit status of echo is 0. Continuing..."
false || {
echo "Command failed. Continuing..."
# do something else
false && true # all commands in the list need to be true
}
false && truedoes not cause an exit because ending expression is evaluated and evaluates to 0. From the bash man page for set -e:
false && true不会导致退出,因为结束表达式被计算并计算为 0。从 bash 手册页为set -e:
Exit immediately if a pipeline (which may consist of a single simple command), a subshell command enclosed in parentheses, or one of the commands executed as part of a command list enclosed by braces (see SHELL GRAMMAR above) exits with a non-zero status. The shell does not exit if the command that fails ispart of the command list immediately following a while or until keyword, part of the test following the ifor elif reserved words, part of any command executed in a && or || list except the command following the final && or ||, any command in a pipeline but the last, or if the command's return value is being inverted with !. A trap on ERR, if set, is executed before the shell exits. This option applies to the shell environment and each subshell environment separately (see COMMAND EXECUTION ENVIRONMENT above), and may cause subshells to exit before executing all the commands in the subshell.
如果管道(可能由单个简单命令组成)、括在括号中的子 shell 命令或作为大括号括起来的命令列表的一部分执行的命令之一(请参阅上面的 SHELL GRAMMAR)以非零值退出,则立即退出地位。如果失败的命令是紧跟在 while 或 until 关键字之后的命令列表的一部分、在 if或 elif 保留字之后的测试的一部分、在 && 或 || 中执行的任何命令的一部分,则 shell 不会退出 除了最后一个 && 或 || 之后的命令之外的列表,管道中除最后一个之外的任何命令,或者如果命令的返回值正在用 ! 反转。如果设置了 ERR 上的陷阱,则会在 shell 退出之前执行。此选项分别适用于shell环境和每个子shell环境(参见上面的命令执行环境),并且可能导致子shell在执行子shell中的所有命令之前退出。
Only last command if executed in ||/&&chain can trigger exit.
只有在||/&&链中执行的最后一条命令才能触发退出。
The following expression will fail from the reason above.
由于上述原因,以下表达式将失败。
true && false
but the following will not:
但以下不会:
if true && false
then
true
fi
because of true && falseis part of test following if.
因为true && false是以下测试的一部分if。
回答by jilles
The behaviour of set -eis unintuitive in all but the simplest cases and has changed several times over the years. Therefore I do not recommend using it except in really simple scripts (plain sequences of commands).
set -e除了最简单的情况外,的行为在所有情况下都是不直观的,并且多年来发生了多次变化。因此,除了非常简单的脚本(简单的命令序列)外,我不建议使用它。
Note that commands in a Makefile are usually executed with set -ein effect, so it is still often needed to understand something about how it works.
请注意,Makefile 中的命令通常是有效执行的set -e,因此通常仍需要了解其工作原理。
The &&and ||operators allow a similar effect with relatively little clutter, but make it explicit. In particular, a &&might be placed at the end of a line much like a `;'.
在&&与||运营商允许以相对较少的杂波类似的效果,但要明确的。尤其是,a&&可能像‘;’一样放在一行的末尾。

