“ sh兼容”是什么意思?


63

我已经看到了通常在引用shell时使用的“ shcompatible”一词。我不确定它是否也适用于可能在Shell中运行的程序。

Shell或其他程序“与sh兼容”是什么意思?“ sh不兼容”是什么意思?

编辑:这个问题问bash和sh之间的区别非常相关: sh和bash之间的区别

我仍然想直接回答“与Windows兼容”的含义。一个合理的期望可能是“ sh兼容”的意思是“实现Shell命令语言”,但是为什么会有那么多的“ sh兼容” shell,又为什么又不同呢?


1
对于shell脚本,它是指该脚本是否使用与Bourne Shell(sh)兼容(可运行)的语法。对于其他Shell,它是指该Shell是否可以运行Bourne Shell脚本。
HalosGhost 2014年

如果你想学习弹的发明者,你可以在参观我的回答unix.stackexchange.com/questions/45684/...
波斯湾

Answers:


116

为什么有那么多“ sh兼容” shell?

Bourne shell的首次公开于1979年发布了作为一部分的Unix V7。由于几乎每个Unix和类似Unix的系统都是从V7 Unix派生而来的 -即使只是在精神上也如此-Bourne外壳对我们来说是“永远的”。¹

Bourne shell实际上取代了Thompson shell的早期外壳,但是它在Unix历史上就这么早发生,以至于今天几乎被人们遗忘了。Bourne外壳是Thompson外壳的超集。²

伯恩(Bourne)和汤普森(Thompson)弹都被称为shPOSIX指定外壳也称为sh。因此,当有人说sh-compatible时,他们是在手工提及这个系列的shell。如果要具体说明,可以说“ POSIX shell”或“ Bourne shell”。³

POSIX的壳是基于1988年版本的KornShell,而这又是为了更换伯恩上AT&T的Unix外壳,跨越式的BSD C外壳程序中features.⁴在一定程度上的术语,其ksh是POSIX壳的祖先,最Unix和类似Unix的系统包括今天的Korn shell的某些变体。通常,例外情况是微型嵌入式系统,它们无法承受完整的POSIX shell占用的空间。

就是说,Korn Shell(与POSIX Shell有所不同)从未真正在商业Unix世界之外流行。这是因为它的兴起与Unix商业化的早期相对应,因此它陷入了Unix战争。BSD Unixes避开了它,转而使用C shell,并且它的源代码在启动时就无法在Linux中免费使用。⁵因此,当早期的Linux发行商开始寻找与Linux内核一起使用的命令shell时,他们通常选择GNU Bash,这是sh您正在谈论的兼容产品之一。⁶

Linux和击之间,早期的关联几乎密封的其他许多炮弹,包括命运kshcshtcsh。如今仍有顽固分子使用这些弹药,但在少数人中却很。⁷

所有这些历史解释了为什么相对较晚的创建者喜欢bashzshyash选择使其sh兼容:为什么Bourne / POSIX兼容性是类Unix系统要获得广泛采用所必须提供的最低外壳。

在许多系统中,默认的交互式命令外壳和/bin/sh是不同的东西。/bin/sh也许:

  • 原始的伯恩贝壳。这在较早的UNIX®系统中很常见,例如Solaris 10(于2005年发行)及其前身。⁸

  • POSIX认证的外壳。这在较新的UNIX®系统中很常见,例如Solaris 11(2010)。

  • Almquist外壳。这是最初于1989年在Usenet上发布的开源Bourne / POSIX shell克隆,然后被伯克利的CSRG贡献,使其包含在第一个不包含AT&T源代码4.4BSD-Lite的 BSD版本中。Almquist shell通常被称为ash,即使安装为/bin/sh

    4.4BSD-Lite继而成为所有现代BSD派生工具的基础,并且/bin/sh在大多数情况下仍保留为Almquist派生工具,但以下是一个主要例外。您可以在NetBSDFreeBSD的源代码存储库中看到这种直接下降的关系:它们从第一天开始就交付Almquist Shell衍生物。

    ashBSD世界之外有两个重要的分支:

    1. dash,在2006年被Debian和Ubuntu广泛采用为默认/bin/sh实现。(Bash仍然是Debian衍生产品中的默认交互式命令外壳。)

    2. BusyBox中ash命令,在嵌入式Linux中经常使用,可用于实现。由于晚于它,它是从Debian的老衍生,我选择考虑它的衍生物,而不是,尽管内BusyBox的命令名。/bin/shdashashdashash

      (BusyBox的还包括一个不太多特征的替代ashhush。通常只有两个人会被内置到任何给定的BusyBox的二进制文件:ash默认情况下,但是hush,如果空间实在紧张。因此,/bin/sh基于BusyBox的系统并不总是dash。类似的)

  • GNU Bash当称为时会禁用其大多数非POSIX扩展sh

    除Debian及其衍生版本外,此选择通常在Linux的台式机和服务器版本上使用。自2003年发布Panther以来,Mac OS X也已做到这一点。

  • 带有ksh93POSIX扩展名的shell,例如OpenBSD。尽管OpenBSD Shell更改了行为以避免使用Bourne和POSIX Shell时语法和语义上的不兼容,当sh它被称为时,它并不会禁用其任何纯扩展名,因为它们不会与旧版Shell发生冲突。

    这是不常见的。您不应该期望中的ksh93功能/bin/sh

我在上面使用“ shell脚本”作为通用术语,表示Bourne / POSIX shell脚本。这是由于伯恩家族的炮弹无处不在。要谈论其他shell上的脚本,您需要提供一个限定符,例如“ C shell脚本”。即使在C系列外壳为默认交互式外壳的系统上,最好使用Bourne外壳进行脚本编写。

它告诉我们,当Wikipedia对Unix Shell进行分类时,它们将它们分为Bourne Shell兼容,C Shell兼容和“其他”。

该图可能会有所帮助:

Unix Shell:Bourne,Korn,POSIX,C和rc Shell系列

(单击以获取SVG版本31 kB,或查看完整尺寸的PNG版本 218 kB。)

“ sh不兼容”是什么意思?

谈论不sh兼容的事物通常意味着以下三件事之一:

  1. 他们指的是那些“其他”外壳之一。

  2. 他们在Bourne和C shell系列之间进行区分。

  3. 他们谈论的是一个Bourne家族外壳中的某些特定功能,而不是所有其他Bourne家族外壳中的特定功能。ksh93bashzsh,尤其是旧版“标准”外壳程序中不存在的许多功能。一旦您超出了共享的POSIX / ksh88基础,这三者在许多方面也是相互不兼容的。

在shell脚本的顶部写上#!/bin/sh shebang行,但在其中使用Bash或Korn shell扩展是一个经典的错误。由于这/bin/sh是当今许多系统上上面的Korn / POSIX族图中的shell之一,因此此类脚本将在所编写的系统上工作,但随后/bin/sh在更广泛的Bourne shell系列中起作用的系统上失败。最佳实践是使用#!/bin/bash#!/bin/ksh扩展行(如果脚本使用此类扩展名)。

有很多方法可以检查给定的Bourne家族外壳脚本是否可移植:

  • checkbashisms在Debian项目中运行该工具,该工具将检查脚本中的“ bashisms”

  • posh在Debian软件包库中的一个shell 下运行它,该shell有意仅实现SUS3指定的功能以及其他一些次要功能

  • 在Schily Tools项目中运行它osh该项目是Sun于2005年作为OpenSolaris的一部分开源的Bourne shell的改进版本,使其成为在现代计算机上获得1979年样式的Bourne shell的最简单方法之一。

    Schily Tools发行版还包括boshPOSIX类型的shell,具有许多非标准功能,但对于测试旨在在所有POSIX家族shell上运行的shell脚本的兼容性可能很有用。它往往是在其功能设置比更保守bashzsh和的增强版本ksh93

    Schily Tools还包含一个名为的外壳bsh,但这是一个历史古怪的东西,根本不是Bourne家族的外壳。

  • 仔细阅读GNU Autoconf手册中的“ 可移植外壳编程”一章。您可能会意识到它在脚本中讨论的一些有问题的构造。

他们为什么不同?

出于同样的原因,所有“新功能和改进功能!” 情况有所不同:

  • 只能通过取消向后兼容性来改进改进的版本。

  • 有人想到了一种更好的工作方式,这是他们更喜欢的,但是与旧的工作方式不同。

  • 有人尝试在完全不了解旧标准的情况下重新实现旧标准,因此他们搞砸了,并造成了无意间的差异。


脚注和旁白

  1. BSD Unix的早期版本只是V6 Unix的附加软件集合。由于Bourne外壳直到V7才被添加到AT&T Unix中,因此BSD从技术上讲并没有Bourne外壳。BSD对Thompson shell原始特性的回答是C shell

    尽管如此,BSD的第一个独立版本(2.9BSD和3BSD)是基于V7或其可移植的后继UNIX / 32V的,因此它们确实包含了Bourne shell。

    (该2BSD线变成BSD数字的的平行叉PDP小型机,而3BSD和4BSD线接着利用更新的计算机类型等的优点VaxenUnix工作站 2.9BSD基本上4.1cBSD的PDP版本; 他们同期,并共享代码。PDP的不只是消失在VAX到达,所以2BSD线仍然 步履蹒跚 一起。)

    可以肯定地说,到1983年,Bourne外壳在Unix世界中无处不在。MS-DOS有一个分层文件系统,一年(噢,怎么cuuute!)和第24位的Macintosh及其9" B&W的屏幕-而不是灰度显示,从字面上黑色白色 -不出来,直到年初明年。

  2. 从今天的标准来看,Thompson外壳非常原始。它只是一个交互式命令外壳,而不是我们今天期望的脚本编程环境。它确实具有诸如管道和I / O重定向之类的东西,我们通常将其视为“ Unix shell”的一部分,因此我们将MS-DOS命令shell视为从Unix获取它们。

    伯恩壳也取代了PWB壳,它增加了重要的事情汤普森壳等可编程(ifswitchwhile)和环境变量的早期形式。由于PWB shell不是Unix的每个版本的一部分,因此它的记忆力甚至不如Thompson shell。

  3. 当某人不确定 POSIX与Bourne外壳的兼容性时,可能会涉及很多方面。

    在一个极端情况下,他们可能会使用1979年的Bourne贝壳作为基线。一个“ sh兼容脚本”在这个意义上就意味着它有望在真正Bourne shell或任何其继承人和克隆的完美运行:ashbashkshzsh,等。

    另一个极端是,有人以POSIX指定的外壳作为基准。如今,我们将POSIX shell的众多功能视为“标准”,以至于我们常常忘记它们实际上并没有出现在Bourne shell中:内置算术,作业控制,命令历史,别名,命令行编辑,$()命令形式替代等

  4. 尽管Korn shell的历史可以追溯到1980年代初期,但AT&T直到1988 年System V Release 4才将它运用于Unix。由于有如此多的商业Unix基于SVR4,因此ksh几乎将所有相关的商业Unix引入了该版本。从1980年代后期开始。

    (基于SVR3的一些怪异的Unix风格在SVR4发行之后就一直占据着市场,但是当革命来临时,它们是第一个碰壁。)

    1988年也是第一个POSIX标准问世的一年,它的Korn外壳基于“ POSIX外壳”。后来,在1993年,出现了Korn shell的改进版本。由于POSIX有效地将原版钉牢,因此ksh分叉成两个主要版本:ksh88ksh93,以参与拆分的年份命名。

    ksh88尽管差异很小,但并不完全与POSIX兼容,因此某些ksh88外壳程序版本已打补丁为与POSIX兼容。(这是在Slashdot上与David G. Korn博士进行的一次有趣的访谈。是的,是写壳的那个人。)

    ksh93POSIX shell的完全兼容的超集。自从主要源代码存储库从AT&T 移至GitHub以来,其开发工作ksh93一直是零星的,而在我撰写本文时,最新版本大约是3年以前,即ksh93v。(项目的基本名称保留有后缀,以表示1993年以后的发行版本。)ksh93

    包含Korn外壳作为与POSIX外壳分开的对象的系统通常使它作为可用/bin/ksh,尽管有时它隐藏在其他地方。

    当谈及kshKorn shell的名称时,我们所谈论的ksh93功能是将其与向后兼容的Bourne和POSIX shell子集区分开来。您很少遇到纯洁的ksh88今天。

  5. AT&T保留Korn shell源代码专有,直到2000年3月。到那时,Linux与GNU Bash的联系非常牢固。Bash和Bash ksh93 相互之间有优势,但是在这一点上,惯性使Linux与Bash紧密相关。

    至于为什么早期的Linux厂商最常选择GNU猛砸了pdksh,这可以在Linux的起步的时候,我想这是因为有那么多的用户空间的其余部分也来到了GNU项目。Bash也比先进一些pdksh,因为Bash开发人员并不局限于复制Korn shell功能。

    pdkshAT&T将源代码发布到真正的Korn shell时,停止了工作。但是,仍然有两个主要的分支:OpenBSD pdkshMirBSD Korn Shell ,mksh

    我发现有趣的mksh是,这是目前为Cygwin打包的唯一Korn shell实现。

  6. GNU Bash在很多方面都超越了POSIX,但是您可以要求它以更纯净的POSIX模式运行

  7. csh/ tcsh通常是1990年代初期BSD Unix上的默认交互式shell。

    作为BSD的一种变体,Mac OS X的早期版本就是通过Mac OS X 10.2“ Jaguar”实现的。OS X tcshOS X 10.3“ Panther”中将默认Shell从Bash 切换为Bash 。此更改不会影响从10.2或更早版本升级的系统。这些转换后的系统上的现有用户保留了他们的tcsh外壳。

    FreeBSD 声称仍将tcsh用作默认外壳程序,但是在我在这里的FreeBSD 10 VM上,默认外壳程序似乎是POSIX兼容的Almquist外壳程序变体之一。在NetBSD上也是如此。

    OpenBSD使用fork pdksh作为默认外壳。

    Linux和OS X的日益普及使某些人希望FreeBSD也可以切换到Bash,但是出于哲学原因,他们不会很快这样做。如果麻烦的话,切换起来容易

  8. 如今,很少有系统具有真正的香草伯恩壳/bin/sh。您必须竭尽所能找到足够接近它的东西以进行兼容性测试。

    我所知道的唯一一个运行一个现代化的计算机上一个真正的1979年的老式Bourne shell的方式:用古代的Unix V7与磁盘映像SIMH PDP-11模拟器计算机历史仿真项目。SIMH几乎可以在每台现代计算机上运行,而不仅仅是Unix类计算机。SIMH甚至可以在AndroidiOS上运行。

    借助OpenSolarisSun首次开源了Bourne Shell的SVR4版本。在此之前,仅具有Unix源代码许可证的用户才能使用Bourne Shell的V7后版本的源代码。

    现在,可以从几个不同的来源分别从已终止的OpenSolaris项目中获得该代码。

    最直接的资源是Heirloom Bourne shell项目。在最初的OpenSolaris 2005发行之后不久,该功能就可用了。在接下来的几个月中完成了一些可移植性和错误修复工作,但随后该项目的开发暂停了。

    JörgSchilling的Schily Tools软件包中osh在维护此代码的版本方面做得更好。有关更多信息,请参见上文。

    请记住,这些衍生自2005年源代码发行版的shell包含多字节字符集支持,作业控制,shell函数以及其他原始1979 Bourne shell中不存在的功能。

    判断您是否在原始Bourne外壳上的一种方法是查看它是否支持添加的未记录功能以简化从Thompson外壳的过渡:^作为的别名|。就是说,类似的命令ls ^ more将在Korn或POSIX类型的shell上给出错误,但ls | more在真正的Bourne shell 上将表现出错误。

  9. 有时你会遇到一个fishscshrc/es贴壁,但他们不是C壳球迷甚至罕见。

    rc弹的家庭不常用的Unix / Linux系统,但家庭是具有重要历史意义,这是怎么赚上面的图中的位置。rcBell Labs操作系统的Plan 9的标准外壳,它是10版Unix的后继版本,它是Bell Labs对操作系统设计进行持续研究的一部分。在编程级别上它与Bourne和C shell不兼容;那里可能有一个教训。

    最活跃的变体rc似乎是Toby Goodwin维护的变体,它基于rcByron Rakitzis 的Unix 克隆。


如果您想了解更多的关系,例如与UNOS的“ command”,“ bsh”和最近的Bourne Shell的关系,请给我发笔记。提示:UNOS命令具有内置命令“ do”,该命令充当带参数的单行shell脚本。这个想法以“ dosh”的身份转移到了Bourne Shell中,并允许使用可参数化的别名,这是您无法通过ksh或bash获得的。
2015年

可能值得注意的是pdksh本身是基于Forsyth shell的。今天大多数人都忘记了它,但在pdksh的遗产中确实具有一定的历史意义,但也因为它是某些minix版本的外壳,并已移植到msdos。
斯特凡Chazelas

25

“ sh兼容”是指POSIXsh,它是所有兼容系统上必须存在的基本shell。一个与sh兼容的脚本应该在任何与POSIX兼容的机器上都可以工作。

之所以必须这样说,是因为通常/bin/sh是的符号链接/bin/bash,它使某些Bashism陷入了声明自己要sh与with 一起使用的脚本中#!/bin/sh。这些脚本无法在不用bash作as的系统上运行/bin/sh,包括永远的一些商业Unices 以及最近的Debian及其衍生产品

特别是最近有一种趋势,即使用dashDebian Almquish Shell作为默认值sh,因为它更小且速度更快。这种趋势突显了许多原本应为sh脚本的Bashism 。将其描述为“与sh兼容”表示它明确地打算通过完全保持在POSIX指定的语言之内而与这些系统一起工作—所有shell都将实现该功能的超集,因此可以保证在任何地方都可以使用,但是它们的扩展名不是彼此兼容。

不同的Shell具有各自的开发历史,并且随着时间的推移在不同的方向上有所不同,因为它们添加了功能来帮助用户进行交互使用或编写脚本扩展(如关联数组)。“ sh不兼容”脚本将使用其中的一些非标准扩展功能,例如Bash的[[条件语句。

bashtcshzsh以及所有其他当前Shell 的非POSIX功能非常有用,并且在很多情况下您可能需要或需要它们。只是不应该在声明自己可以使用的脚本中使用它们/bin/sh,因为您不能依赖sh运行于系统上的基本实现中的那些功能。

确实需要使用关联数组的脚本应确保它与bash而不是一起运行sh

#!/bin/bash
declare -A array

可以在任何地方使用bash。不需要扩展功能并且打算可移植的脚本应声明它们使用sh并坚持使用基本的shell命令语言。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.