我最近用我编写的shell脚本擦除了我的主目录的一部分。幸运的是,我确实以足够快的速度击中 Ctrl - C 以避免最坏的情况。
我的错误在于过分依赖相对路径。从现在开始,我总是在更改目录时使用绝对路径...但是,它引出了一个有趣的问题:编写健壮的shell脚本有哪些规则?
我已经知道,当从目录移动到另一个目录时,应始终使用绝对路径。但是,必须有很多其他的(例如,当命令失败时该怎么做,什么是停止脚本并告知用户有关它的好方法。)
那么,是否有人列出了专门针对shell脚本的规则和提示?
答案 0 :(得分:11)
一些想法:
在shebang中使用-e
标志,例如#!/bin/sh -e
。这样脚本将在第一个错误时停止。这有点像在Java中抛出RuntimeException
。这可能确实拯救了我的屁股几次,我觉得在这种情况下它也会帮助你。
处理脚本中所有语句的退出代码。实际上在shebang中使用-e
会强迫你这样做。
请勿使用;
链接命令。请改用&&
。同样,在shebang中使用-e
会强迫你这样做。
正确引用可能包含空格或其他特殊字符的路径。
最好是在没有参数的情况下使用脚本时不会做危险的事情。
对于非平凡的脚本,请确保-h
和--help
标记打印有用的消息。 (我使用this script生成带有标志解析的脚本。)对于在没有参数的情况下调用时可以执行危险操作的脚本,这应该是必需的。
在任何非正常退出时使用显式exit 1
退出脚本。处理if
块中的错误,echo
一些有用的消息,然后exit
没有任何参数,这是一个常见的错误。由于exit
使用最后一个命令的退出代码,在本例中为echo
,因此它将成功退出。请注意,在我之前链接的示例脚本中,在处理exit 1
标记后打印帮助消息后我--help
。
如果您不需要bash
功能,请使用#!/bin/sh
shebang并尝试与旧版本保持兼容。我认为,便携式是一种坚固性。
使用$()
代替``
。更容易阅读~~更难犯错误。
很好地一致地格式化代码。更容易阅读~~健壮。
请注意平台之间的差异。例如,date --iso
和date +%F
都以2013-11-17
格式打印日期,但第一个仅适用于GNU系统,第二个也适用于BSD和Solaris。所以始终使用date +%F
,它无处不在。当然有100个这样的例子。如果你正在做一些你不习惯的事情,那么试着检查它是否也适用于不同的系统。
测试空变量,尤其是在rm -fr
等危险命令中。例如,如果TOPDIR或/和OBJDIR恰好为空或未设置,则rm -rf "$TOPDIR/$OBJDIR"
的结果可能是灾难性的。通常,仔细检查或三重检查危险命令的可能参数值,如下所示。
不要超越shell脚本的限制。脚本应该是胶水代码。如果你发现自己做了一些棘手的事情,或者你需要晦涩难懂的功能,那么你最好转向更强大的语言。
最后,这些都不会阻止你犯下愚蠢的错误。
PS:我会继续回来并添加更多东西,因为我记得它们。请随时建议改进,我会添加它们。感谢。
答案 1 :(得分:3)
一般规则:你需要考虑你正在做的事情。测试和调试是实现成功的一种方式。
无论您使用何种语言,始终会分解问题。写小程序。测试他们。必要时修复。使用小的编写更复杂的。等等。
了解给定语言的调试工具。在bash中,-x选项可以为您创造奇迹。此外,战略性地放置echo foo
或echo $variable
可以为您提供很多帮助。
如果您需要做一些具有潜在破坏性的事情(比如删除文件),请首先进行干运行。将所有rm
替换为echo
并检查结果。如果发生了错误,您将在要删除的文件列表中看到它。
测试数据准备的每一步。甚至,如果你在bash中写一个单行,在添加管道和另一个阶段之前检查每个阶段的结果。及早发现问题并尽早解决问题。
确保解决方案具有可扩展性。如果它为你工作了20个数据项,它会工作20万个吗?
如果您的程序处理用户提供的数据,请确保即使是输入垃圾也能以理智的方式运行。在这种情况下,报告错误并退出是一种理智的方式。
瞄准简单。解决方案越简单,就越容易避免错误。
并且 - 当然 - 我忘了在这里添加一些重要的东西:)
祝你好运!