Stu*_*ent 1 shell shell-script portability
几个月来我一直热衷于 shell 脚本编写,发现我编写的代码(在bash
)在某些机器上不起作用。这是非常令人失望的。
我意识到我应该学习最便携的 shell 脚本。当然,这在开始时会有点痛苦,但我相信它最终会得到回报。我希望我的 shell 脚本几乎可以在任何地方使用,包括 Linux 系列和 BSD 系列。(但我不在乎它们是否在 Windows 上运行。)
最便携的外壳是什么?编辑:请忽略这个问题
使用最便携的外壳有哪些严重的缺点?编辑:请忽略这个问题
如果我想编写极其便携的代码,我还应该注意什么?例如,我应该使用和避免使用哪些核心实用程序以及哪些版本?
您的bash
脚本应该在任何bash
安装了shell 的机器上工作,除非您使用的bash
功能对于其他系统上的 shell 版本来说太新,例如,尝试使用名称引用 ( declare -n
)、关联数组 ( declare -A
) 或macOS上的默认%(...)T
格式printf
(或任何其他不同的东西)的格式bash
(这是古老的;bash
在这种情况下,只需使用 Homebrew安装更新的格式)。如果您的脚本使用其他系统上不可用的外部工具,或者可能未实现或以不同方式实现的工具功能,它们也可能会失败。
POSIX 系统上最便携的 shell 语言是sh
shell。这在这里描述:https : //pubs.opengroup.org/onlinepubs/9699919799/idx/shell.html
该bash
壳(等)实施sh
,进行了扩展。有些外壳,比如fish
或zsh
,甚至根本不想成为sh
外壳(但通过zsh
提供了一定程度的“-sh
仿真” --emulate sh
),而外壳 likedash
确实试图更纯粹地符合 POSIXsh
标准(但仍然有一些扩展)。
一般来说,与语法和内置特性相关的 shell 方面应该是“可移植的”,只要脚本总是由同一个 shell(和 shell 版本,在某种程度上)执行,即使该 shell 恰好是fish
贝壳。这与 Python、Perl 和 Ruby 脚本具有相同类型的“可移植性”。然而有应始终是sh
可用的壳(通常是安装成/bin/sh
),通常是bash
,dash
,或ksh
在某种形式的“兼容模式”运行。
POSIX 系统上最便携的实用程序是 POSIX 实用程序。这些在此处描述:https : //pubs.opengroup.org/onlinepubs/9699919799/idx/utilities.html
GNU 实用程序,即 中的那些coreutils
,实现了 POSIX 实用程序(正如用户 schily在评论中指出的那样,这并不意味着它们符合POSIX标准),然后通过主要为了方便起见的功能对其进行了扩展。对于其他 Unix 系统上的相应实用程序也是如此。还要注意的是GNU coreutils
Linux上的包不包含所有实用程序,POSIX指定和实用程序,如find
,sed
,awk
,等,这些都是POSIX公用事业,分别包装。
只要您继续使用 POSIX 实用程序并使用它们的 POSIX 行为(在选项等方面),在使用 POSIXsh
语法的脚本中,您就可能在大多数 Unix 系统上“主要是可移植的”。但也要注意,非 POSIX 实用程序和非 POSIX 对 POSIX 实用程序的扩展仍然相当可移植,因为它们通常被实现。的普通的非POSIX实用程序的实例是pkill
,tar
,和gzip
。非POSIX扩展POSIX实用程序,共同找到的例子是-iname
的谓词find
和事实sed
往往可以制成明白延长使用正则表达式-E
。
通过自己测试(例如在虚拟机中)以及阅读本网站上的问题和答案,您将了解哪些工具的实现中的哪些扩展、在哪些 Unices 上运行、以何种方式运行。例如,如何使用 sed -i(就地编辑)实现可移植性?
另请注意,在某些情况下,POSIX 标准会留下“未指定”行为,这意味着在两个不同的 Unix 系统上,使用 POSIX 选项的相同实用程序可能表现不同。在为什么在符号链接更新到具有权限OK 的新目标时权限被拒绝?
尝试编写纯 POSIX shell 代码的缺点是您会错过一些真正有用的功能。我曾经尝试find
为该 GNU 的-readable
谓词测试编写 POSIX 等效测试,这并不容易,并且尝试使用ps
andgrep
而不是pkill
这个站点上的一些太多问题的主题来通过名称来表示进程。同样,尝试“保持 POSIX”,您将需要远离真正有用的东西,例如perl
,并且您将无法轻松完成任何管理任务(添加用户、管理备份、在系统之间传输文件等)。
一般来说,我更喜欢务实的方法来完成任务,同时理解我的代码可能需要修改以支持其他系统(如果它曾经在其他系统上使用过),而不是纯粹的方法。这并没有阻止我编写我知道将具有尽可能少的可移植性问题的脚本(我不会在任何地方使用不可移植的语义)。但这是我个人的看法。