编写健壮的shell脚本有哪些规则?

时间:2013-11-17 18:38:59

标签: shell robustness

我最近用我编写的shell脚本擦除了我的主目录的一部分。幸运的是,我确实以足够快的速度击中 Ctrl - C 以避免最坏的情况。

我的错误在于过分依赖相对路径。从现在开始,我总是在更改目录时使用绝对路径...但是,它引出了一个有趣的问题:编写健壮的shell脚本有哪些规则?

我已经知道,当从目录移动到另一个目录时,应始终使用绝对路径。但是,必须有很多其他的(例如,当命令失败时该怎么做,什么是停止脚本并告知用户有关它的好方法。)

那么,是否有人列出了专门针对shell脚本的规则和提示?

2 个答案:

答案 0 :(得分:11)

一些想法:

  1. 在shebang中使用-e标志,例如#!/bin/sh -e。这样脚本将在第一个错误时停止。这有点像在Java中抛出RuntimeException。这可能确实拯救了我的屁股几次,我觉得在这种情况下它也会帮助你。

  2. 处理脚本中所有语句的退出代码。实际上在shebang中使用-e会强迫你这样做。

  3. 请勿使用;链接命令。请改用&&。同样,在shebang中使用-e会强迫你这样做。

  4. 正确引用可能包含空格或其他特殊字符的路径。

  5. 最好是在没有参数的情况下使用脚本时不会做危险的事情。

  6. 对于非平凡的脚本,请确保-h--help标记打印有用的消息。 (我使用this script生成带有标志解析的脚本。)对于在没有参数的情况下调用时可以执行危险操作的脚本,这应该是必需的。

  7. 在任何非正常退出时使用显式exit 1退出脚本。处理if块中的错误,echo一些有用的消息,然后exit没有任何参数,这是一个常见的错误。由于exit使用最后一个命令的退出代码,在本例中为echo,因此它将成功退出。请注意,在我之前链接的示例脚本中,在处理exit 1标记后打印帮助消息后我--help

  8. 如果您不需要bash功能,请使用#!/bin/sh shebang并尝试与旧版本保持兼容。我认为,便携式是一种坚固性。

  9. 使用$()代替``。更容易阅读~~更难犯错误。

  10. 很好地一致地格式化代码。更容易阅读~~健壮。

  11. 请注意平台之间的差异。例如,date --isodate +%F都以2013-11-17格式打印日期,但第一个仅适用于GNU系统,第二个也适用于BSD和Solaris。所以始终使用date +%F,它无处不在。当然有100个这样的例子。如果你正在做一些你不习惯的事情,那么试着检查它是否也适用于不同的系统。

  12. 测试空变量,尤其是在rm -fr等危险命令中。例如,如果TOPDIR或/和OBJDIR恰好为空或未设置,则rm -rf "$TOPDIR/$OBJDIR"的结果可能是灾难性的。通常,仔细检查或三重检查危险命令的可能参数值,如下所示。

  13. 不要超越shell脚本的限制。脚本应该是胶水代码。如果你发现自己做了一些棘手的事情,或者你需要晦涩难懂的功能,那么你最好转向更强大的语言。

  14. 最后,这些都不会阻止你犯下愚蠢的错误。

    PS:我会继续回来并添加更多东西,因为我记得它们。请随时建议改进,我会添加它们。感谢。

答案 1 :(得分:3)

一般规则:你需要考虑你正在做的事情。测试和调试是实现成功的一种方式。

无论您使用何种语言,始终会分解问题。写小程序。测试他们。必要时修复。使用小的编写更复杂的。等等。

了解给定语言的调试工具。在bash中,-x选项可以为您创造奇迹。此外,战略性地放置echo fooecho $variable可以为您提供很多帮助。

如果您需要做一些具有潜在破坏性的事情(比如删除文件),请首先进行干运行。将所有rm替换为echo并检查结果。如果发生了错误,您将在要删除的文件列表中看到它。

测试数据准备的每一步。甚至,如果你在bash中写一个单行,在添加管道和另一个阶段之前检查每个阶段的结果。及早发现问题并尽早解决问题。

确保解决方案具有可扩展性。如果它为你工作了20个数据项,它会工作20万个吗?

如果您的程序处理用户提供的数据,请确保即使是输入垃圾也能以理智的方式运行。在这种情况下,报告错误并退出是一种理智的方式。

瞄准简单。解决方案越简单,就越容易避免错误。

并且 - 当然 - 我忘了在这里添加一些重要的东西:)

祝你好运!