如何编写跨平台的Shell脚本?

5
我有一个shell脚本需要在多个平台上运行,这些平台都支持bash。我的问题是一些命令在Linux、FreeBSD、OS X和Cygwin上的表现不同。我目前的思路是:
- 在主脚本中创建所有操作系统特定操作的默认实现,然后检查 $OSTYPE 并 source 特定于实现的文件(可选),以替换表现不同的命令。但如果这样做,应该如何处理带有多个参数的命令?四个位置参数传递给一个函数并不是最清晰的方法。 - 将所有实现放在我的脚本中,每个名称都有一个后缀,在名称中检查 $OSTYPE 并创建一个 OPSUFFIX 变量,然后为每个操作调用 operation$OPSUFFIX。 - 通过 ./configure 魔法? - 迁移到类似Python的东西——也许是最明智的选择,但需要最多的代码更改。但如果这是惯用的 init 脚本,则这不是一个选项。

如果你想要真正跨平台的东西,那么你需要从脚本语言迁移到编程语言 - 有许多语言可以将操作系统实现与代码分离; Python、Ruby、Java 只是其中几种。如果你让 Windows 用户安装 Cygwin(呕吐),那么让他们安装其他语言也不是什么大问题。 - Boris the Spider
许多标准命令在大部分操作方面都有标准化的行为。如果你能够保持在这个区域内(并且能够使用 bash,这并不是你可以合理断言的东西),那么你通常可以编写一个大部分可移植的脚本。 - Etan Reisner
1
@BoristheSpider 对于使用 Cygwin 或 UWin 作为自己的工作流程的一部分,特别是用于跨平台使用脚本,没有任何问题。我不知道人们如何在没有 Cygwin 的情况下生存。 - ormaaj
1
POSIX(可移植操作系统接口)就是为了这个目的而定义的。如果您坚持使用 POSIX 规范定义的命令,并且只使用 POSIX 定义的选项,那么您的脚本将具有尽可能的可移植性。此外,您可以考虑使用 POSIX 的 sh 而不是 bash 编写脚本,以便脚本可以在任何(兼容 POSIX 的)shell 中运行。 - chepner
这在很大程度上取决于您在脚本中想要做什么(例如:文件位置、名称、行为)。我经常在AIX/SUN/Linux上这样做,不幸的是,我会根据操作系统/版本创建特定行为列表并使脚本超载。请注意,sed的使用因版本和操作系统而异,或者仅仅是管道行为有时需要一个新行(SUN),而其他操作系统则不需要。 - NeronLeVelu
@chepner 你说得对,关于bash,我不认为有一个POSIX的adduser命令。 - David Ehrmann
1个回答

1
首先,尽可能找到不会影响结果的方法来完成你想要的事情。例如,某些版本的tar不支持处理gzipped文件的“-z”选项。但是,将tar和gzip组合使用是可移植的。同样,有一些调用ps的方法通常在BSD和LINUX上都能正常工作。
一旦你发现仍然需要处理的问题,你提供函数处理命令语法的方法似乎是合理的。为了避免位置参数,你可以使用bash内置的getopt。
另一种选择可能是编写一个Python脚本或类似的东西,只是封装了最糟糕的平台相关命令行行为。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接