同样,问题很简单...
'set -e'是什么?这样做,为什么会被认为是危险的?
#1 楼
如果任何子命令或管道返回非零状态,则set -e
导致外壳退出。访问者可能正在寻找的答案是:
在创建init.d脚本时使用“ set -e”是危险的:
来自http://www.debian.org/doc/debian-policy/ch-opersys.html 9.3.2-
请注意在init.d脚本中使用set -e。编写正确的init.d脚本要求在守护程序已经运行或已经停止时接受各种错误退出状态,而不会中止init.d脚本,并且使用int -e调用常见的init.d函数库并不安全。对于init.d脚本,通常不使用set -e而不是分别检查每个命令的结果通常会更容易。
从访问者的角度来看,这是一个有效的问题,因为它可以衡量应聘者具有服务器级脚本和自动化的工作知识
评论
好点子。从技术上讲,这可能会导致启动过程暂停,但从技术上来说这可能是错误的,但不应导致整个脚本停止运行
–马特
2012年9月19日下午2:29
尽管我同意stackoverflow.com/questions/78497/…,但我认为这种样式非常适合bash用于短期init检查和日志记录或其他环境猴子修补,然后再执行目标工作负载。我们对docker镜像使用相同的策略初始化脚本。
– joshperry
17年6月6日在3:52
#2 楼
来自bash(1)
: -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 is part of the command
list immediately following a while or until keyword,
part of the test following the if or 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 envi-
ronment separately (see COMMAND EXECUTION ENVIRONMENT
above), and may cause subshells to exit before executing
all the commands in the subshell.
很不幸,我没有足够的创意去思考为什么它会很危险,除了“脚本的其余部分不会执行”之外或“它可能可能掩盖了实际问题”。
评论
掩盖真实/其他问题,是的,我想我可以看到...我也在努力举一个例子说明它很危险。
–cpbills
2010年5月19日在16:48
有设置的手册页!我总是以buildin(1)结尾。谢谢。
–Jared Beck
13年5月29日在23:27
我怎么知道set的文档将在man 1 bash中找到?以及如何在如此巨大的手册页中为set关键字找到-e选项?你不能/ -e在这里搜索
– phil294
17-6-5在6:33
@Blauhirn使用帮助集
– phil294
18年3月13日在22:04
#3 楼
应当注意,可以为脚本的各个部分打开和关闭set -e
。整个脚本的执行不必一定要启用。甚至可以有条件地启用它。就是说,我从不使用它,因为我自己进行错误处理(或不进行错误处理)。some code
set -e # same as set -o errexit
more code # exit on non-zero status
set +e # same as set +o errexit
more code # no exit on non-zero status
另外值得注意的是Bash手册页上的
trap
命令,该命令还描述了set -e
在某些情况下的功能。如果失败的命令立即是
命令列表的一部分,则不执行
ERR陷阱。在一段时间或直到关键字之后,
if语句中的部分测试,在&&或⎪⎪列表中执行的部分命令
,或者该命令的返回值被反转
通过!这些是
errexit选项所遵循的相同条件。
因此在某些情况下,非零状态不会导致退出。
我认为危险在于不了解
set -e
何时起作用以及何时不起作用以及在某些无效假设下错误地依赖它。另请参见BashFAQ / 105为什么不起作用设置-e(或设置-o errexit或陷阱ERR)是否达到了我的期望?
评论
虽然稍微偏离了这个问题,但这个答案正是我要寻找的:只在脚本的一小部分将其关闭!
–斯蒂芬·比杰斯特(Stephan Bijzitter)
17年11月9日在10:18
#4 楼
请记住,这是求职面试的一项测验。这些问题可能是当前员工写的,可能是错误的。这并不一定很糟糕,每个人都会犯错,面试问题通常位于一个黑暗的角落,没有经过审查,只有在面试过程中才会出现。没有什么我们认为“危险的”。但是该问题的作者可能会错误地认为“ set -e”是危险的,因为他们自己的无知或偏见。也许他们写了一个有问题的shell脚本,遭到了轰炸,然后他们错误地以为“ set -e”应归咎于他们,而实际上他们却忽略了编写适当的错误检查。我参加了在过去的两年中,可能有40次面试,而面试官有时会提出错误的问题或有错误的答案。
或者这是一个棘手的问题,虽然很la脚,但并不完全出乎意料。
或者这是一个很好的解释:http://www.mail-archive .com / debian-bugs-dist @ lists.debian.org / msg473314.html
评论
+1我在同一条船上,而我一直在进行的许多“技术”面试至少被误导了。
–cpbills
2010年5月19日在17:43
哇。在debian列表上很好找到。 +1是对面试问题的无知。我记得自从100%确信自己是对的以来就曾经争论过一次netback答案。他们说不。我回家搜索了一下,我是对的。
–egorgry
2010年5月19日在18:48
#5 楼
set -e
告诉bash在脚本中,只要任何东西返回非零的返回值就退出。权限,并且在再次限制它们之前,脚本已死。评论
那很有意思。我没有考虑过在过早终止的脚本中打开权限,但是我可以看到这被认为是危险的。这个测验的有趣之处在于,您不能使用任何参考资料,例如man或google;如果不能完全回答,则根本不要回答。
–egorgry
2010年5月19日17:02
那真是愚蠢,我会重新考虑这个老板...开玩笑(有点)。拥有强大的知识基础是一件好事,但是一半的IT工作是知道/ where /查找信息...希望他们足够聪明,可以在为申请人评分时考虑到这一点。在旁注中,我看到/ no /用于set -e,实际上,对我而言,它懒惰地忽略了脚本中的错误检查...因此,请与该雇主一起记住这一点...如果他们经常使用它,它们的脚本是什么样的,您将不可避免地需要维护...
–cpbills
2010年5月19日17:45
好点@cpbills。在脚本中我也看不到set -e的用处,这可能就是为什么它让我如此沮丧的原因。我想发布所有问题,因为有些问题真的很好,有些却像古怪而随意。
–egorgry
2010年5月19日在18:46
我已经在许多系统Cron工作中看到了...
–安德鲁(Andrew)
2010年5月20日,0:29
#6 楼
如果遇到非零退出代码,则在某些情况下,set -e
将终止脚本。用几句话总结使用它的危险:它不符合人们的想法。我认为,它应该被视为危险的hack,出于兼容性考虑,它仍然存在仅用于目的。
set -e
语句不会将shell从使用错误代码的语言转换为使用类似异常控制流的语言,而只是极力地尝试模仿这种行为。Greg Wooledge有很多话要说。
set -e
的危险:https://www.mail-archive.com/bug-bash@gnu.org/msg19497.html(最近的邮件列表帖子有一个有趣的类比)
http://mywiki.wooledge.org/BashFAQ/105(有关
set -e
陷阱的Wiki页面)在第二个链接中,有
set -e
的非直觉和不可预测行为的各种示例。set -e
的非直觉行为的一些示例(某些摘自上面的Wiki链接):set -e x=0 let x++ echo "x is $x"
上面的内容将导致shell脚本过早退出,因为
let x++
返回0,let
关键字将其视为虚假值并将其转换为非零退出代码。 set -e
注意到了这一点,并以静默方式终止了脚本。 尽管唯一的区别在于已将单行重构为函数,但上述内容将在
/opt/foo
不存在的情况下终止。这是因为它最初起作用的事实是/opt/foo
行为的特殊例外。当set -e
返回非零值时,它将被a && b
忽略。但是,既然它是一个函数,则该函数的退出代码等于该命令的退出代码,并且返回非零的函数将以静默方式终止脚本。set -e [ -d /opt/foo ] && echo "Warning: foo is already installed. Will overwrite." >&2 echo "Installing foo..."
上面的内容将从文件
set -e
中读取数组config_vars
。正如作者可能打算的那样,如果缺少config
,它将以错误终止。正如作者可能不希望的那样,如果config
没有以换行符结尾,则它默默终止。如果此处未使用config
,则set -e
将包含该文件的所有行,无论该文件是否以换行符结尾。请注意Sublime Text的用户(以及其他错误处理换行符的文本编辑器)。 set -e check_previous_install() { [ -d /opt/foo ] && echo "Warning: foo is already installed. Will overwrite." >&2 } check_previous_install echo "Installing foo..."
作者可能会合理地期望,如果由于某种原因,用户
config_vars
不存在,则$user
命令将失败,脚本将终止而不是让用户未经审核即可执行某些任务。但是,在这种情况下,groups
终端永远不会生效。如果由于某种原因找不到set -e
,则$user
函数不会终止脚本,而只是返回错误的数据,就像should_audit_user
无效一样。这适用于从条件部分调用的任何函数。一个
set -e
语句,无论嵌套的深度如何,无论它在何处定义,即使您再次在其中运行if
,也是如此。在任何时候使用set -e
会完全禁用if
的效果,直到条件块完全执行为止。如果作者不了解此陷阱,或者在可能调用函数的所有可能情况下都不了解其整个调用堆栈,则他们将编写错误的代码,并且set -e
提供的错误安全感至少会部分怪。即使作者完全意识到了这一缺陷,解决方法是以与不使用
set -e
时编写代码的方式相同的方式编写代码,从而有效地减少了该开关的浪费。作者不仅必须编写手动错误处理代码,就像set -e
无效一样,而且set -e
的存在可能使他们误以为他们不必这样做。 set -e
的其他一些缺点:它鼓励草率的代码。错误处理程序完全被遗忘了,希望发生任何故障都会以某种明智的方式报告错误。但是,对于上面的类似
set -e
的示例,情况并非如此。如果脚本意外死机,通常是静默的,这会妨碍调试。如果脚本没有消失,而您希望它能够死掉(请参见前面的要点),那么您手上将会有一个更加微妙和隐蔽的错误。它会使人们产生一种错误的安全感。再次参见
let x++
-condition的要点。shell终止的位置在shell或shell版本之间不一致。由于
if
的行为在这些版本之间进行了调整,因此可能意外地编写了在旧版本的bash上表现不同的脚本。它周围的问题建议您反对它,而其他一些人则建议在它主动知道陷阱时小心谨慎。有许多shell脚本新手在所有脚本上推荐set -e
作为错误条件的综合解决方案,但在现实生活中,这种方式行不通。set -e
不能代替教育。#7 楼
我说这很危险,因为您不再控制他的脚本流了。只要脚本调用的任何命令返回非零值,脚本就可以终止。因此,您要做的就是做一些改变任何组件的行为或输出的操作,然后终止主脚本。这可能更多是样式问题,但肯定会带来后果。如果您的主脚本应该设置一些标志,但不是因为它提前终止,该怎么办?如果它假定该标志应该存在,或者使用意外的默认值或旧值,您最终都会对系统的其余部分造成错误。评论
完全同意这个答案。这并不是天生的危险,但是这是一个意外退出的机会。
– pboin
2010年5月20日,0:18
这让我想起了我的C ++教授,因为我在程序中没有单个入口点/单个出口点,所以总是从我的分配中提取点。我以为这纯粹是“原则”,但是这套e生意肯定演示了事情如何以及为什么会完全失控。最终,程序是关于控制和确定性的,如果提前终止,您将同时放弃这两种方法。
–马辛
2010年5月20日上午11:45
#8 楼
作为@Marcin回答的一个具体示例,这个问题已经使我深深地咬住了我,想像一下您的脚本中某处有rm foo/bar.txt
行。如果foo/bar.txt
实际上不存在,通常没什么大不了的。但是现在有了set -e
,您的脚本将在那里提前终止!糟糕。
评论
这是一个相关的线程:stackoverflow.com/questions/64786/error-handling-in-bash / ...