bash 何时使用 set -e
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 
原文地址: http://stackoverflow.com/questions/13468481/
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
When to use set -e
提问by dimba
I come across set -ea some time ago and I admit I love it. 
Now, after some time I'm back to write some bash scripting.
我set -e前段时间遇到过,我承认我喜欢它。现在,一段时间后我回来编写一些 bash 脚本。
My question is if there are some best practices when to use set -eand when not to use it (.e.g. in small/big scripts etc.) or should I rather use a pattern like cmd || exit 1to track errors?
我的问题是是否有一些最佳实践何时使用set -e和何时不使用它(例如在小/大脚本等中)还是我应该使用像cmd || exit 1跟踪错误这样的模式?
回答by andrewdotn
Yes, you should always use it. People make fun of Visual Basic all the time, saying it's not a real programming language, partly because of its “On Error Resume Next” statement. Yet that is the default in shell! set -eshould have been the default. The potential for disaster is just too high.
是的,您应该始终使用它。人们一直取笑 Visual Basic,说它不是真正的编程语言,部分原因是它的“On Error Resume Next”声明。然而这是shell中的默认值!set -e应该是默认的。灾难的可能性太高了。
In places where it's ok for a command to fail, you can use || trueor it's shortened form ||:, e.g.
在命令失败的地方,你可以使用|| true或者它的缩写形式||:,例如
grep Warning build.log ||:
In fact you should go a step further, and have
事实上,你应该更进一步,并有
set -eu
set -o pipefail
at the top of every bashscript.
在每个bash脚本的顶部。
-umakes it an error to reference a non-existent environment variable such as ${HSOTNAME}, at the cost of requiring some gymnastics with checking ${#}before you reference ${1}, ${2}, and so on.
-u引用不存在的环境变量(例如 )会导致错误,${HSOTNAME}代价是${#}在引用${1}、 等之前需要进行一些检查${2}。
pipefailmakes things like misspeled-command | sed -e 's/^WARNING: //'raise errors.
pipefail使诸如misspeled-command | sed -e 's/^WARNING: //'引发错误之类的事情发生。
回答by Greg A. Woods
If your script code checks for errors carefully and properly where necessary, and handles them in an appropriate manner, then you probably don't ever need or want to use set -e.
如果您的脚本代码在必要时仔细正确地检查错误,并以适当的方式处理它们,那么您可能永远不需要或不想使用set -e.
On the other hand if your script is a simple sequential list of commands to be run one after another, and if you want the script to terminate if any one of those fail, then sticking set -eat the top would be exactly what you would want to do to keep your script simple and uncluttered.  A perfect example of this would be if you're creating a script to compile a set of sources and you want the compile to stop after the first file with errors is encountered.
另一方面,如果您的脚本是一个一个接一个运行的简单命令顺序列表,并且如果您希望脚本在其中任何一个失败时终止,那么坚持set -e在顶部将正是您想要做的使您的脚本保持简单和整洁。一个完美的例子是,如果您正在创建一个脚本来编译一组源代码,并且您希望在遇到第一个有错误的文件后停止编译。
More complex scripts can combine these methods since you can use set +eto turn its effect back off again and go back to explicit error checking.
更复杂的脚本可以组合这些方法,因为您可以使用set +e它再次关闭其效果并返回到显式错误检查。
Note that although set -eis supposed to cause the shell to exit IFFany untestedcommand fails, it is wise to turn it off again when your code is doing its own error handling as there can easily be weird cases where a command will return a non-zero exit status that you're not expecting, and possibly even such cases that you might not catch in testing, and where sudden fatal termination of your script would leave something in a bad state.  So, don't use set -e, or leave it turned on after using it briefly, unless you really know that you want it.
请注意,虽然set -e应该导致 shell 退出IFF,但任何未经测试的命令失败,当您的代码执行自己的错误处理时再次关闭它是明智的,因为很容易出现命令返回非零的奇怪情况您没有预料到的退出状态,甚至可能是您在测试中可能无法捕捉到的情况,以及脚本的突然致命终止会使某些内容处于不良状态。所以,不要使用set -e,或者在短暂使用后让它保持开启状态,除非你真的知道你想要它。
Note also that you can still define an error handler with trap ERRto do something on an error condition when set -eis in effect, as that will still be run before the shell exits.
另请注意,您仍然可以定义一个错误处理程序,trap ERR以便set -e在生效时对错误条件执行某些操作,因为它仍将在 shell 退出之前运行。
回答by F. Hauri
You loveit!?
你喜欢它!?
For my self, I prefer in a wide, having in my .bashrca line like this:
就我自己而言,我更喜欢宽泛的,在我.bashrc的一行中是这样的:
trap '/usr/games/fortune /usr/share/games/fortunes/bofh-excuses' ERR
( on debian: apt-get install fortunes-bofh-excuses:-)
(在 debian 上:apt-get install fortunes-bofh-excuses:-)
But it's only my preference ;-)
但这只是我的偏好;-)
More seriously
更认真
lastErr() {
    local RC=$?
    history 1 |
         sed '
  s/^ *[0-9]\+ *\(\(["'\'']\)\([^]*\)\|\([^"'\'' ]*\)\) */cmd: \"\", args: \"/;
  s/$/", rc: '"$RC/"
}
trap "lastErr" ERR
Gna
bash: Gna : command not found
cmd: "Gna", args: "", rc: 127
Gna gna
cmd: "Gna", args: "gna", rc: 127
"Gna gna" foo
cmd: "Gna gna", args: "foo", rc: 127
Well, from there, you could:
那么,从那里,你可以:
trap "lastErr >>/tmp/myerrors" ERR
"Gna gna" foo
cat /tmp/myerrors 
cmd: "Gna gna", args: "foo", rc: 1
Or better:
或更好:
lastErr() {
local RC=$?
history 1 |
     sed '
  s/^ *[0-9]\+ *\(\(["'\'']\)\([^]*\)\|\([^"'\'' ]*\)\) */cmd: \"\", args: \"/;
  s/$/", rc: '"$RC/
  s/^/$(date +"%a %d %b %T ")/"
}
"Gna gna" foo
cat /tmp/myerrors 
cmd: "Gna gna", args: "foo", rc: 1
Tue 20 Nov 18:29:18 cmd: "Gna gna", args: "foo", rc: 127
... You could even add other informations like $$, $PPID, $PWDor maybe your..
...您甚至可以添加其他信息,例如$$, $PPID, $PWD或者您的..
回答by Saddam Abu Ghaida
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 列表的一部分,也不是以 ! 保留字,则外壳应立即退出。

