什么是最便携的 shell,以及要遵循的相关最佳实践?

Stu*_*ent 1 shell shell-script portability

几个月来我一直热衷于 shell 脚本编写,发现我编写的代码(在bash)在某些机器上不起作用。这是非常令人失望的。

我意识到我应该学习便携的 shell 脚本。当然,这在开始时会有点痛苦,但我相信它最终会得到回报。我希望我的 shell 脚本几乎可以在任何地方使用,包括 Linux 系列和 BSD 系列。(但我不在乎它们是否在 Windows 上运行。)

问题

  1. 最便携的外壳是什么?编辑:请忽略这个问题

  2. 使用最便携的外壳有哪些严重的缺点?编辑:请忽略这个问题

  3. 如果我想编写极其便携的代码,我还应该注意什么?例如,我应该使用和避免使用哪些核心实用程序以及哪些版本?

Kus*_*nda 7

您的bash脚本应该在任何bash安装了shell 的机器上工作,除非您使用的bash功能对于其他系统上的 shell 版本来说太新,例如,尝试使用名称引用 ( declare -n)、关联数组 ( declare -A) 或macOS上的默认%(...)T格式printf(或任何其他不同的东西)的格式bash(这是古老的;bash在这种情况下,只需使用 Homebrew安装更新的格式)。如果您的脚本使用其他系统上不可用的外部工具,或者可能未实现或以不同方式实现的工具功能,它们也可能会失败。

POSIX 系统上最便携的 shell 语言是shshell。这在这里描述:https : //pubs.opengroup.org/onlinepubs/9699919799/idx/shell.html

bash壳(等)实施sh,进行了扩展。有些外壳,比如fishzsh,甚至根本不想成为sh外壳(但通过zsh提供了一定程度的“-sh仿真” --emulate sh),而外壳 likedash 确实试图更纯粹地符合 POSIXsh标准(但仍然有一些扩展)。

一般来说,与语法内置特性相关的 shell 方面应该是“可移植的”,只要脚本总是由同一个 shell(和 shell 版本,在某种程度上)执行,即使该 shell 恰好是fish贝壳。这与 Python、Perl 和 Ruby 脚本具有相同类型的“可移植性”。然而有应始终是sh可用的壳(通常是安装成/bin/sh),通常是bashdash,或ksh在某种形式的“兼容模式”运行。

POSIX 系统上最便携的实用程序是 POSIX 实用程序。这些在此处描述:https : //pubs.opengroup.org/onlinepubs/9699919799/idx/utilities.html

GNU 实用程序,即 中的那些coreutils,实现了 POSIX 实用程序(正如用户 schily在评论中指出的那样,这并不意味着它们符合POSIX标准),然后通过主要为了方便起见的功能对其进行了扩展。对于其他 Unix 系统上的相应实用程序也是如此。还要注意的是GNU coreutilsLinux上的包不包含所有实用程序,POSIX指定和实用程序,如findsedawk,等,这些都是POSIX公用事业,分别包装。

只要您继续使用 POSIX 实用程序并使用它们的 POSIX 行为(在选项等方面),在使用 POSIXsh语法的脚本中,您就可能在大多数 Unix 系统上“主要是可移植的”。但也要注意,非 POSIX 实用程序和非 POSIX 对 POSIX 实用程序的扩展仍然相当可移植,因为它们通常被实现。的普通的非POSIX实用程序的实例是pkilltar,和gzip。非POSIX扩展POSIX实用程序,共同找到的例子是-iname的谓词find和事实sed往往可以制成明白延长使用正则表达式-E

通过自己测试(例如在虚拟机中)以及阅读本网站上的问题和答案,您将了解哪些工具的实现中的哪些扩展、在哪些 Unices 上运行、以何种方式运行。例如,如何使用 sed -i(就地编辑)实现可移植性?

另请注意,在某些情况下,POSIX 标准会留下“未指定”行为,这意味着在两个不同的 Unix 系统上,使用 POSIX 选项的相同实用程序可能表现不同。在为什么在符号链接更新到具有权限OK 的新目标时权限被拒绝?

尝试编写纯 POSIX shell 代码的缺点是您会错过一些真正有用的功能。我曾经尝试find为该 GNU 的-readable谓词测试编写 POSIX 等效测试,这并不容易,并且尝试使用psandgrep而不是pkill这个站点上的一些太多问题的主题来通过名称来表示进程。同样,尝试“保持 POSIX”,您将需要远离真正有用的东西,例如perl,并且您将无法轻松完成任何管理任务(添加用户、管理备份、在系统之间传输文件等)。

一般来说,我更喜欢务实的方法来完成任务,同时理解我的代码可能需要修改以支持其他系统(如果它曾经在其他系统上使用过),而不是纯粹的方法。这并没有阻止我编写我知道将具有尽可能少的可移植性问题的脚本(我不会在任何地方使用不可移植的语义)。但这是我个人的看法。

  • @schily 你好。我从未说过它们符合 POSIX。我说他们实现了 POSIX 实用程序。他们遵守实际标准的程度如何,我真的不能说太多,因为我在更大程度上不是 Linux 用户。然而,我会稍微改写这句话,以表明这不是背书。 (2认同)