Pra*_*tic 66 shell compatibility
我已经看到通常在提到 shell 时使用的短语“sh compatible”。我不确定它是否也适用于可能在 shell 中运行的程序。
shell 或其他程序“sh 兼容”是什么意思?“sh不兼容”是什么意思?
编辑:这个问题询问 bash 和 sh 之间的区别非常相关: Difference between sh and bash
我仍然想直接回答“sh 兼容”的含义。一个合理的预期可能是“sh 兼容”意味着“实现了 Shell 命令语言”,但是为什么有这么多“sh 兼容”的 shell,它们为什么不同呢?
War*_*ung 127
为什么有这么多“sh兼容”的shell?
在Bourne shell的首次公开于1979年发布了作为一部分的Unix V7。由于几乎所有 Unix 和类 Unix 系统都源自 V7 Unix——即使只是在精神上——Bourne shell 已经“永远”与我们同在。¹
Bourne shell 实际上取代了早期的 shell,改名为 Thompson shell,但它发生在 Unix 历史的早期,以至于今天几乎被遗忘了。Bourne shell 是 Thompson shell 的超集。²
Bourne 和 Thompson 炮弹都被称为sh. POSIX 指定的shell也称为sh. 所以,当有人说sh-compatible 时,他们是在指这一系列的 shell。如果他们想具体一点,他们会说“POSIX shell”或“Bourne shell”。³
POSIX shell 是基于 1988 年版本的KornShell,这反过来又是为了取代 AT&T Unix 上的 Bourne shell,在功能方面超越BSD C shell。?到的程度ksh是POSIX外壳的祖先,大多数Unix和类Unix系统,包括今天在Korn shell的一些变种。例外情况通常是微型嵌入式系统,它们无法承受完整的 POSIX shell 所占用的空间。
也就是说,Korn shell——作为一个不同于 POSIX shell 的东西——从来没有真正在商业 Unix 世界之外流行过。这是因为它的兴起与Unix商业化的早期相对应,所以它被卷入了Unix战争。BSD Unixes 避开它而支持 C shell,并且它的源代码在 Linux 开始时不能免费使用。?所以,当早期的 Linux 发行商去寻找一个命令 shell 来与他们的 Linux 内核搭配时,他们通常选择GNU Bash,sh你正在谈论的那些兼容之一。?
Linux 和 Bash 之间的早期关联几乎决定了许多其他 shell 的命运,包括ksh,csh和tcsh. 今天仍然有顽固分子在使用这些炮弹,但他们非常少。?
所有这些历史都解释了为什么相对较晚的开发者喜欢bash、zsh和 并yash选择使它们sh兼容:Bourne/POSIX 兼容性是类 Unix 系统的 shell 必须提供的最低限度,以便获得广泛采用。
在许多系统中,默认的交互式命令shell 和shell/bin/sh是不同的东西。/bin/sh或许:
原始的伯恩外壳。这在较旧的 UNIX® 系统中很常见,例如 Solaris 10(2005 年发布)及其前身。
POSIX 认证的外壳。这在较新的 UNIX® 系统中很常见,例如 Solaris 11 (2010)。
该Almquist外壳。这是一个开源的 Bourne/POSIX shell 克隆,最初于 1989 年在 Usenet 上发布,然后被贡献给伯克利的CSRG以包含在第一个不包含 AT&T 源代码的 BSD 版本4.4BSD-Lite 中。Almquist shell 经常被调用ash,即使安装为/bin/sh.
4.4BSD-Lite 转而成为所有现代 BSD 衍生品的基础,其中/bin/sh大部分仍然是 Almquist 衍生品,下面指出了一个主要例外。您可以在NetBSD和FreeBSD的源代码存储库中看到这种直接后代:它们从第一天起就发布了 Almquist shell 衍生产品。
ash在 BSD 世界之外有两个重要的分支:
dash,著名的 Debian 和 Ubuntu在 2006 年采用作为默认/bin/sh实现。(Bash 仍然是Debian 衍生产品中默认的交互式命令 shell。)
BusyBox 中的ash命令,在嵌入式 Linux 中经常使用,可用于实现. 由于它已过期并且源自 Debian 的旧软件包,我选择将其视为而非的衍生物,尽管它的命令名称是在 BusyBox 中。/bin/shdashashdashash
(BusyBox 还包含一个功能较弱的替代方法ash调用hush。通常,任何给定的 BusyBox 二进制文件中只会构建两者之一:ash默认情况下,hush但当空间非常紧张时。因此,/bin/sh在基于 BusyBox 的系统上并不总是dash类似。)
GNU Bash,它在调用时禁用大部分非 POSIX 扩展sh。
这种选择在 Linux 的桌面和服务器变体上很典型,但 Debian 及其衍生产品除外。自 2003 年发布 Panther 以来,Mac OS X 也已经这样做了。
一个带有ksh93POSIX 扩展的 shell,就像在 OpenBSD 中一样。尽管 OpenBSD shell 更改行为以避免在调用 as 时与 Bourne 和 POSIX shell 的语法和语义不兼容sh,但它不会禁用其任何纯扩展,即与旧 shell 不冲突的扩展。
这并不常见;你不应该期望ksh93在特征/bin/sh。
我在上面使用了“shell 脚本”作为通用术语,意思是 Bourne/POSIX shell 脚本。这是由于 Bourne 家族贝壳无处不在。要讨论在其他 shell 上编写脚本,您需要给出一个限定词,例如“C shell 脚本”。即使在 C 系列 shell 是默认交互式 shell 的系统上,最好使用 Bourne shell 编写脚本。
当维基百科对 Unix shell 进行分类时,他们将它们分为 Bourne shell 兼容、C shell 兼容和“其他”。
此图可能有帮助:
(单击 SVG 版本,31 kB,或查看全尺寸 PNG 版本,218 kB。)
“sh不兼容”是什么意思?
有人谈论不sh兼容的事情通常意味着以下三件事之一:
他们指的是那些“其他”贝壳之一。?
他们正在区分 Bourne 和 C shell 系列。
他们正在谈论一个 Bourne 系列外壳中的某些特定功能,而所有其他 Bourne 系列外壳中都没有。ksh93, bash,zsh尤其是具有许多旧“标准”外壳中不存在的功能。一旦超出共享的 POSIX/ksh88基础,这三者在很多方面也是互不兼容的。
编写在顶部带有#!/bin/sh shebang 行的 shell 脚本但在其中使用 Bash 或 Korn shell 扩展是一个典型的错误。由于/bin/sh如今在如此多的系统上是上述 Korn/POSIX 系列图中的 shell 之一,因此此类脚本将在编写它们的系统上运行,但在/bin/sh来自更广泛的 Bourne shell 家族的系统上失败。如果脚本使用此类扩展名,最佳实践是使用#!/bin/bash或#!/bin/kshshebang 行。
有很多方法可以检查给定的 Bourne 系列 shell 脚本是否可移植:
运行checkbashisms它,这是一个来自 Debian 项目的工具,用于检查“ bashisms ”脚本。
posh在 Debian 软件包存储库中的一个 shell下运行它,该 shell 特意仅实现SUS3指定的功能,以及一些其他次要功能。
下运行它obosh从在席利工具项目于2005年,是Bourne shell的改进版本开放孙源作为OpenSolaris的一部分,使其成为获得1979年的风格Bourne shell的现代计算机的最简单方法之一。
Schily Tools 发行版还包括bosh一个具有许多非标准功能的 POSIX 类型 shell ,但它可能有助于测试打算在所有 POSIX 系列 shell 上运行的 shell 脚本的兼容性。它往往是它的功能不止保守bash,zsh和的增强版本ksh93。
Schily Tools 还包括一个名为 的外壳bsh,但这是一个历史上的奇怪现象,它根本不是 Bourne 家族的外壳。
仔细阅读GNU Autoconf 手册中的便携式 Shell 编程章节。您可能会发现它在您的脚本中提到的一些有问题的结构。
他们为什么不同?
出于同样的原因,所有“新的和改进的!” 事情是不同的:
改进后的版本只能通过破坏向后兼容性来改进。
有人想出了一种不同的工作方式,他们更喜欢这种方式,但这与旧的工作方式不同。
有人在没有完全理解的情况下尝试重新实现旧标准,因此他们搞砸了并造成了无意的差异。
脚注和旁注:
BSD Unix 的早期版本只是 V6 Unix 的附加软件集合。由于 Bourne shell 直到 V7 才被添加到 AT&T Unix,因此 BSD 从技术上讲并没有开始拥有 Bourne shell。BSD 对 Thompson shell 的原始性质的回答是C shell。
尽管如此,BSD 的第一个独立版本(2.9BSD 和 3BSD)基于 V7 或其可移植的后续版本UNIX/32V,因此它们确实包含了 Bourne shell。
(2BSD 产品线变成了用于 Digital 的PDP 小型机的 BSD 的并行分支,而 3BSD 和 4BSD 产品线继续利用更新的计算机类型,如Vaxen和Unix 工作站。2.9BSD 本质上是 4.1cBSD 的 PDP 版本;它们是同时期和共享代码。当 VAX 到来时,PDP 并没有消失,所以 2BSD 线仍然 蹒跚前 行。)
可以肯定地说,到 1983 年,Bourne shell 在 Unix 世界中无处不在。这是计算行业“永远”的一个很好的近似值。MS-DOS有一个分层文件系统,一年(噢,怎么cuuute!)和第24位的Macintosh及其9" B&W的屏幕-而不是灰度,从字面上黑色和白色-不出来,直到年初明年。
按照今天的标准,Thompson shell 是相当原始的。它只是一个交互式命令外壳,而不是我们今天期望的脚本编程环境。它确实有管道和 I/O 重定向之类的东西,我们认为它们是“Unix shell”的原型部分,因此我们认为MS-DOS 命令 shell是从 Unix 获取它们的。
Bourne shell 还取代了 PWB shell,后者为 Thompson shell 添加了重要的东西,比如可编程性(if、switch和while)和环境变量的早期形式。PWB shell 比 Thompson shell 更难记住,因为它不是每个版本的 Unix 的一部分。
当有人对 POSIX 与 Bourne shell 的兼容性没有特别了解时,他们可能意味着很多事情。
在一种极端情况下,他们可能会使用 1979 年的 Bourne shell 作为他们的基线。一个“sh兼容脚本”在这个意义上就意味着它有望在真正Bourne shell或任何其继承人和克隆的完美运行:ash,bash,ksh,zsh,等。
另一个极端的人假设 POSIX 指定的 shell 作为基线。如今,我们将许多 POSIX shell 功能视为“标准”,以至于我们经常忘记它们实际上并未出现在 Bourne shell 中:内置算术、作业控制、命令历史、别名、命令行编辑、$()命令形式替代等。
尽管 Korn shell 的根源可以追溯到 1980 年代早期,但 AT&T 直到1988年System V Release 4才在 Unix 中发布它。由于如此多的商业 Unix 基于 SVR4,这使得ksh几乎所有相关的商业 Unix 从1980 年代后期开始。
(在SVR4 发布之后,一些基于SVR3和更早版本的奇怪 Unix 风格在市场上占有一席之地,但当革命到来时,它们是第一个靠墙的。)
1988 年也是第一个POSIX 标准问世的一年,其基于 Korn shell 的“POSIX shell”。后来,在 1993 年,出现了 Korn shell 的改进版本。由于 POSIX 有效地将原始ksh版本固定到位,分为两个主要版本:ksh88和ksh93,以他们分裂所涉及的年份命名。
ksh88虽然差异很小,但并不完全兼容 POSIX,因此某些版本的ksh88shell 被修补为兼容 POSIX。(这是来自Slashdot 对 David G. Korn 博士的有趣采访。是的,编写 shell 的人。)
ksh93是POSIX shell 的完全兼容超集。自从主要源代码存储库从 AT&T 迁移到 GitHub以来,开发ksh93一直是零星的,在我写这篇文章时,最新版本大约有 3 年的历史,ksh93v。(该项目的基本名称保留了后缀以表示 1993 年以后的发行版本。)ksh93
包含 Korn shell 作为独立于 POSIX shell 的东西的系统通常使其可用作为/bin/ksh,尽管有时它隐藏在其他地方。
当我们谈论ksh或 Korn shell 时,我们谈论的ksh93是将其与向后兼容的 Bourne 和 POSIX shell 子集区分开来的功能。你ksh88今天很少遇到纯净的。
AT&T 将 Korn shell 源代码保留到 2000 年 3 月为止。到那时,Linux 与 GNU Bash 的联系非常牢固。Bash 和ksh93 每个都比另一个优势,但在这一点上惯性使 Linux 与 Bash 紧密相关。
至于为何早期的Linux厂商最常选择GNU猛砸了pdksh,这是可以在Linux的起步的时候,我想这是因为有那么多的用户空间的其余部分也来到了GNU项目。Bash 也比 更先进pdksh,因为 Bash 开发人员并不局限于复制 Korn shell 功能。
pdkshAT&T 将源代码发布到真正的 Korn shell 时,工作停止了。有迹象表明,仍保持然而,两个主要的叉:OpenBSD的pdksh和MirBSD Korn外壳,mksh。
我觉得有趣的mksh是,这是目前为 Cygwin 打包的唯一 Korn shell 实现。
GNU Bash 在很多方面都超越了 POSIX,但您可以要求它以更纯粹的 POSIX 模式运行。
csh/tcsh通常是 1990 年代早期 BSD Unix 上的默认交互式 shell。
作为 BSD 变体,Mac OS X 的早期版本就是这样,通过 Mac OS X 10.2“Jaguar”。OS Xtcsh在OS X 10.3 "Panther"中将默认 shell 从Bash切换到了 Bash 。此更改不影响从 10.2 或更早版本升级的系统。这些转换后的系统上的现有用户保留了他们的tcshshell。
FreeBSD声称仍tcsh用作默认 shell,但在我这里的 FreeBSD 10 VM 上,默认 shell 似乎是与 POSIX 兼容的Almquist shell 变体之一。在 NetBSD 上也是如此。
OpenBSD 使用 forkpdksh作为默认 shell。
Linux 和 OS X 的更高流行度让一些人希望 FreeBSD 也转向 Bash,但出于哲学原因,他们不会很快这样做。如果这困扰您,切换它很容易。
如今,很少能找到具有真正香草 Bourne shell 的系统/bin/sh。您必须竭尽全力找到与它足够接近的东西以进行兼容性测试。
我知道只有一种方法可以在现代计算机上运行真正的 1979年老式Bourne shell:将古代 Unix V7磁盘映像与计算机历史模拟项目中的SIMH PDP-11 模拟器一起使用。SIMH 几乎可以在每台现代计算机上运行,而不仅仅是类 Unix计算机。SIMH 甚至可以在 Android和iOS 上运行。
借助OpenSolaris,Sun首次开源了 Bourne shell 的 SVR4 版本。在此之前,Bourne shell 后 V7 版本的源代码仅对拥有 Unix 源代码许可证的人可用。
该代码现在可以与来自几个不同来源的已失效 OpenSolaris 项目的其余部分分开使用。
最直接的来源是Heirloom Bourne shell 项目。这在 OpenSolaris 的原始 2005 发行版之后不久就可用了。在接下来的几个月中完成了一些可移植性和错误修复工作,但随后项目的开发停止了。
Jörg Schilling 在维护此代码的版本方面做得更好,就像obosh在他的Schily Tools包中一样。有关更多信息,请参见上文。
请记住,这些源自 2005 年源代码版本的 shell 包含多字节字符集支持、作业控制、shell 函数以及原始 1979 Bourne shell 中不存在的其他功能。
判断您是否使用原始 Bourne shell 的一种方法是查看它是否支持添加的未记录功能以简化从 Thompson shell 的转换:^作为|. 也就是说,像这样的命令ls ^ more会在 Korn 或 POSIX 类型的 shell 上给出错误,但它的行为就像ls | more在真正的 Bourne shell 上一样。
有时你会遇到一个fish,scsh或rc/es贴壁,但他们不是C壳球迷甚至罕见。
该rc弹的家庭不常用的Unix / Linux系统,但家庭是具有重要历史意义,它是如何在上图中赢得了一席之地。rc是Bell Labs操作系统的Plan 9的标准 shell,它是第 10 版 Unix的一种继承者,是作为 Bell Labs 对操作系统设计的持续研究的一部分而创建的。它在编程层面与 Bourne 和 C shell 不兼容;那里可能有一个教训。
最活跃的变体rc似乎是由 Toby Goodwin 维护的变体,它基于rcByron Rakitzis的 Unix克隆。
Mic*_*mer 27
“sh 兼容”指的是POSIXsh,这是所有兼容系统上都需要存在的基本 shell。sh 兼容的脚本应该可以在任何 POSIX 兼容的机器上工作。
有必要这么说的原因是它通常/bin/sh是一个符号链接到/bin/bash,这让一些 Bashisms 滑入声明自己使用shwith 的脚本中#!/bin/sh。这些脚本无法在不使用bashas 的系统上运行/bin/sh,包括一些永远的商业 Unices,以及最近的Debian和衍生产品。
特别是最近有一种趋势是使用dashDebian Almquish Shell 作为默认设置sh,因为它更小而且速度更快。这种趋势突出了许多假设sh脚本中的Bashisms 。将某些东西描述为“sh 兼容”表明它明确打算通过完全使用POSIX 指定的语言来与这些系统一起工作——所有 shell 都将实现该功能的超集,因此它保证可以在任何地方工作,但它们的扩展不是彼此兼容。
不同的 shell 有自己的发展历史,随着时间的推移朝着不同的方向发展,因为它们添加了帮助用户交互使用的功能,或者像关联数组这样的脚本扩展。“sh 不兼容”脚本将使用其中一些非标准扩展功能,例如 Bash 的[[条件。
非POSIX功能中bash和tcsh和zsh和所有其他现有炮弹是有用的,而且有很多的情况下,您可能希望或需要它们。它们只是不应该在声明自己与 一起使用的脚本中使用/bin/sh,因为您不能依赖于sh您正在运行的系统上的基本实现中的那些功能。
确实需要使用关联数组的脚本应确保它使用bash而不是sh:
#!/bin/bash
declare -A array
Run Code Online (Sandbox Code Playgroud)
这将在任何地方使用bash. 不需要扩展功能且可移植的脚本应声明它们使用sh并坚持基本 shell 命令语言。