12

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

我的错误是过于依赖相对路径。从现在开始,我在更改目录时总是使用绝对路径……但是,这让我想到了一个有趣的问题:编写健壮的 shell 脚本的规则是什么?

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

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

4

2 回答 2

11

几个想法:

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

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

  3. 不要将命令与;. 改为使用&&。同样,-e在 shebang 中使用会迫使你这样做。

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

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

  6. 对于非平凡的脚本,请确保打印有用的消息-h--help标记。(我使用这个脚本来生成带有标志解析的脚本。)对于那些在没有参数调用时可能会做危险事情的脚本来说,这应该是强制性的。

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

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

  9. 使用$()而不是``. 更容易阅读~~更难犯错误。

  10. 良好且一致地格式化您的代码。更容易阅读~~健壮性。

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

  12. 测试空变量,尤其是在危险的命令中,例如rm -fr. 例如,rm -rf "$TOPDIR/$OBJDIR"如果 TOPDIR 或/和 OBJDIR 恰好为空或未设置,则结果可能是灾难性的。一般来说,对此类危险命令的可能参数值进行双重检查或三重检查。

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

最后,这一切都不会阻止你犯愚蠢的错误。

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

于 2013-11-17T19:26:06.470 回答
3

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

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

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

如果您需要做一些可能具有破坏性的事情(例如删除文件),请先进行试运行。全部替换rmecho并检查结果。如果发生错误,您将在要删除的文件列表中看到该错误。

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

确保解决方案是可扩展的。如果它适用于 20 个数据项,它适用于 20000 个数据项吗?

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

以简单为目标。解决方案越简单,就越容易避免错误。

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

祝你编码好运!

于 2013-11-17T19:19:12.387 回答