我在这里看到测试是否$?为零(成功)或其他内容(失败)是反模式,但我无法在其他任何地方找到它。

与Wikipedia的反模式定义相似:“反模式(或反模式)是对反复出现的问题的普遍反应,这种问题通常无效,并且可能产生适得其反的风险。”为什么这会是反模式?

评论

“通常无效”是该定义中经过深思熟虑的组成部分。如果有一种最佳实践替代方案可以解决主要陷阱或警告,而又​​不会带来任何不利的折衷,则在超过50%的时间工作时,某些事物可能是反模式。确实,有一些反模式之类的东西,因为它们会带来安全风险。一个安全漏洞只需要利用一次就可以使具有该漏洞的代码不可接受,而不是超过50%的执行。

...除非在大多数(但不是全部)反模式的使用中通常无效,除非它表示“通常”;这比较模糊,因此更难以争议。

参见BashPitfalls#44(cmd;((!!??))|| die)。

#1 楼

这是一种反模式,因为它引入了复杂性,如果您根本不需要记录退出状态,就不会存在这种复杂性。

if your_command; then ...


所需要的工作要少得多错误可能比错误的例子要多:例如,请考虑陷阱,甚至添加用于调试的新echo语句,并修改$?。对于读者来说,在视觉上并不明显,运行your_command的单独一行不能在不改变逻辑流程的情况下在其下面添加任何内容。

即:

your_command
if [ "$?" -eq 0 ]; then ...


...正在检查回声,而不是实际命令。


因此,在某些情况下,您确实确实需要以比立即执行更精细的方式处理退出状态分支它的值是否为零,您应该在同一行上收集它:

your_command
echo "Finished running your_command" >&2
if [ "$?" -eq 0 ]; then ...



最后:如果将your_command括在if语句中,这会将其标记为已测试,这样您的外壳程序就不会出于set -eERR陷阱的目的考虑非零退出状态。

因此:

# whitelisting a nonzero value for an example of when "if your_command" won't do.
your_command; your_command_retval=$?
echo "Finished running your_command" >&2 ## now, adding more logging won't break the logic.
case $your_command_retval in
  0|2) echo "your_command exited in an acceptable way" >&2;;
  *)   echo "your_command exited in an unacceptable way" >&2;;
esac


...绝不会(除非困扰set -e行为的一些极端情况和警告)以if以外的任何$?值到达0语句,因为set -e将在这种情况下强制退出。相比之下:

set -e
your_command
if [ "$?" -eq 0 ]; then ...


...将your_command的退出状态标记为已测试,因此不认为它会导致强制按set -e退出脚本。 />

评论


有趣。但是只有当它用作二进制/布尔值时,它才是反模式

– KevinDTimm
16 Mar 30 '16 at 15:30

确实是@KevinDTimm。语言功能已使用;不使用它时不习惯使用它。

–查尔斯·达菲(Charles Duffy)
16 Mar 30 '16 at 15:31

@KevinDTimm,...,标题明确地指出了“查看命令是否成功”的用例-如果该命令遵循零/非零退出状态约定,则确定它是否成功确实是一个布尔决策。

–查尔斯·达菲(Charles Duffy)
16-3-30在15:32



通常将其用作布尔值。对$?的不同非零值采取不同的动作。比较少见

–基思·汤普森(Keith Thompson)
16 Mar 30 '16 at 15:33

经过这么多年的软件编写,除了在早期开发工作中我对调试用输出感兴趣的情况下,我不会再使用不正确的格式。如前所述,不要增加不必要的复杂性。

– KevinDTimm
16 Mar 30 '15:35