前一段时间我遇到set -e
,我承认我喜欢它。
现在,经过一段时间我回来写一些bash脚本。
我的问题是,是否有一些最佳做法何时使用set -e
以及何时不使用它(.eg在小/大脚本中等)或者我应该使用像cmd || exit 1
这样的模式跟踪错误?
答案 0 :(得分:58)
是的,你应该经常使用它。人们总是取笑Visual Basic,说它不是真正的编程语言,部分是因为它的“On Error Resume Next”声明。然而这是shell中的默认值! set -e
应该是默认值。灾难的可能性太大了。
在命令失败的地方,您可以使用|| true
或缩写形式||:
,例如
grep Warning build.log ||:
事实上你应该更进一步,并且
set -eu
set -o pipefail
位于每个bash
脚本的顶部。
-u
使引用不存在的环境变量(例如${HSOTNAME}
)成为错误,代价是在您引用${#}
之前需要一些体操检查${1}
,${2}
,等等。
pipefail
会使misspeled-command | sed -e 's/^WARNING: //'
之类的内容产生错误。
答案 1 :(得分:3)
如果您的脚本代码在必要时仔细并正确地检查错误,并以适当的方式处理它们,那么您可能根本不需要或不想使用set -e
。
另一方面,如果您的脚本是一个接一个地运行的命令的简单顺序列表,并且如果您希望脚本在其中任何一个失败时终止,那么将set -e
放在顶部会正是你想要做的事情,以保持你的脚本简单和整洁。一个完美的例子就是如果您正在创建一个脚本来编译一组源代码,并且您希望在遇到第一个有错误的文件后停止编译。
更复杂的脚本可以组合这些方法,因为您可以使用set +e
再次关闭其效果并返回显式错误检查。
请注意,虽然set -e
应该导致shell退出 IFF ,但任何未经测试的命令都会失败,但是当你的代码再次关闭它时是明智的正在进行自己的错误处理,因为很容易出现奇怪的情况,即命令将返回一个你不期望的非零退出状态,甚至可能发生你可能没有在测试中遇到的情况,以及突然致命终止你的脚本会让事情处于糟糕状态。因此,请不要使用set -e
,或在短暂使用后将其保持开启状态,除非您确实知道自己需要它。
另请注意,您仍然可以使用trap ERR
定义错误处理程序,以便在set -e
生效时执行错误操作,因为在shell退出之前仍会运行。
答案 2 :(得分:3)
你爱它!?
对于我自己,我更喜欢在我的.bashrc
这样的一行:
trap '/usr/games/fortune /usr/share/games/fortunes/bofh-excuses' ERR
(关于debian:apt-get install fortunes-bofh-excuses
: - )
但这只是我的偏好; - )
更严重
lastErr() {
local RC=$?
history 1 |
sed '
s/^ *[0-9]\+ *\(\(["'\'']\)\([^\2]*\)\2\|\([^"'\'' ]*\)\) */cmd: \"\3\4\", 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
那么,从那里,你可以:
trap "lastErr >>/tmp/myerrors" ERR
"Gna gna" foo
cat /tmp/myerrors
cmd: "Gna gna", args: "foo", rc: 1
或更好:
lastErr() {
local RC=$?
history 1 |
sed '
s/^ *[0-9]\+ *\(\(["'\'']\)\([^\2]*\)\2\|\([^"'\'' ]*\)\) */cmd: \"\3\4\", 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
...您甚至可以添加其他信息,例如$$, $PPID, $PWD
或者您的..
答案 3 :(得分:0)
当此选项打开时,如果简单命令因Shell错误的后果中列出的任何原因而失败,或者返回退出状态值> 0,并且在一段时间之后不是复合列表的一部分,直到或if关键字,并且不是AND或OR列表的一部分,并且不是以!开头的管道!保留字,然后贝壳应立即 退出。