你已经落后了。/bin/sh
这些天几乎从来都不是Bourne弹壳,而当它是¹时,当您使用#! /bin/sh
she-bang 时遇到问题。
Bourne外壳是70年代后期编写的外壳,并取代了之前的Thompson外壳(也称为sh
)。在80年代初期,David Korn为Bourne shell编写了一些扩展名,修复了一些错误和设计笨拙(并引入了一些),并将其称为Korn shell。
在90年代初,POSIX 根据Korn Shell的子集指定了sh
语言,大多数系统现在已将其更改/bin/sh
为Korn Shell或符合该规范的Shell。在BSD的情况下,他们逐渐更改了它们的名称/bin/sh
(最初(出于许可原因不再使用Bourne shell)之后),即Almquist shell,它是具有某些ksh扩展名的Bourne shell的克隆,因此符合POSIX。
如今,所有POSIX系统都有一个称为POS的外壳程序sh
(通常,但不一定在/bin
POSIX 中,它不指定其指定的实用程序的路径)。它通常基于ksh88,ksh93,pdksh,bash,ash或zsh²,但不是Bourne shell,因为Bourne shell从不符合POSIX³。几个这些炮弹(bash
,zsh
,yash
和一些pdksh
衍生物时作为调用使POSIX兼容模式sh
,且较少柔顺以其他方式)。
bash
(对Korn外壳的GNU回答)实际上是唯一经过认证的开源外壳(并且可以说只有当前维护,因为其他外壳通常基于ksh88,自90年代以来没有任何新功能)。符合POSIX sh
(作为macOS认证的一部分)。
当使用#! /bin/sh -
she-bang 编写脚本时,应使用标准sh
语法(如果要可移植,还应对脚本中使用的实用程序使用标准语法,解释外壳时不仅涉及外壳,脚本),则sh
使用该标准语法解释器的实现(ksh
,bash
...)都没有关系。
只要您不使用这些外壳,这些外壳都可以扩展标准。就像编写C代码一样,只要您编写标准C代码并且不使用一个编译器(例如gcc
)或另一个编译器的扩展名,则只要编译器兼容,无论编译器实现如何,您的代码都应编译为OK。
在这里,你的#! /bin/sh
她爆炸,你的主要问题将是其中的系统/bin/sh
是Bourne shell的,对于实例不支持标准功能,如$((1+1))
,$(cmd)
,${var#pattern}
...在你可能需要这种情况下,像变通办法:
#! /bin/sh -
if false ^ true; then
# in the Bourne shell, ^ is an alias for |, so false ^ true returns
# true in the Bourne shell and the Bourne shell only.
# Assume the system is Solaris 10 (older versions are no longer maintained)
# You would need to adapt if you need to support some other system
# where /bin/sh is the Bourne shell.
# We also need to fix $PATH as the other utilities in /bin are
# also ancient and not POSIX compatible.
PATH=`/usr/xpg6/bin/getconf PATH`${PATH:+:}$PATH || exit
export PATH
exec /usr/xpg4/bin/sh "$0" "$@"
# that should give us an environment that is mostly compliant
# to the Single UNIX Specification version 3 (POSIX.2004), the
# latest supported by Solaris 10.
fi
# rest of the script
顺便说一句,默认情况下/bin/sh
不是Ubuntu bash
。这是dash
这些天,这是基于NetBSD的外壳sh
,本身基础上,Almquist外壳是主要不同之处在于它不支持多字节字符POSIX兼容。在Ubuntu和其他基于Debian的系统,你可以选择bash
和dash
对/bin/sh
带dpkg-reconfigure dash
)4。sh
Debian附带的脚本在两个Shell中的工作方式应与写入Debian策略标准(POSIX标准的超集)的方式相同。您可能会发现他们还工作确定zsh
的sh
仿真或bosh
(可能不是ksh93
,也不yash
该没有local
内置(由Debian政策而不是POSIX)要求)。
unix.stackexchange.com上范围内的所有系统在sh
某处都有POSIX 。它们中的大多数都有一个/bin/sh
(您可能会发现非常稀有的没有/bin
目录,但您可能并不在意),并且通常使用POSIX sh
解释器(在极少数情况下,可以使用(非标准)Bourne shell) )。
但是,这sh
是您可以确定在系统上找到的唯一Shell解释器可执行文件。对于其他外壳,您可以确定macOS,Cygwin和大多数GNU / Linux发行版都具有bash
。SYSV派生的操作系统(Solaris,AIX ...)通常具有ksh88,可能还有ksh93。OpenBSD,MirOS将具有pdksh派生。macOS将具有zsh
。但除此之外,我们将无法保证。无法保证是否bash
将其他外壳程序安装在/bin
其他任何外壳中(例如,通常在/usr/local/bin
BSD上找到)。当然,也不保证将要安装的外壳版本。
请注意,这#! /path/to/executable
不是约定,它是所有类Unix内核(由Dennis Ritchie于80年代初引入)的功能,它允许通过在第一行中指定解释器的路径来执行任意文件#!
。它可以是任何可执行文件。
当您执行第一行以开头的文件时#! /some/file some-optional-arg
,内核最终/some/file
以some-optional-arg
,脚本的路径和原始参数作为参数执行。您可以在第一行#! /bin/echo test
中查看发生了什么:
$ ./myscript foo
test ./myscript foo
当您使用/bin/sh -
而不是时/bin/echo test
,内核将执行/bin/sh - ./myscript foo
,sh
解释存储在其中的内容代码,myscript
并忽略第一行作为注释(以开头#
)。
¹大概是唯一系统今天的任何人都会遇到一个/bin/sh
是基于Bourne shell是Solaris 10操作系统的Solaris是为数不多的Unix系统是决定继续Bourne shell中的一个出现了向后兼容性(POSIX的sh
语言是不完全向后兼容Bourne Shell)(至少对于台式机和完整服务器部署而言)sh
(其他位置)具有POSIX (/usr/xpg4/bin/sh
基于ksh88,位于中),但在Solaris 11中有所更改,/bin/sh
现在为ksh93。其他的大多数都已失效。
² 所述/bin/sh
的MacOS / X曾经是zsh
,但后来改变到bash
。zsh
用作POSIX sh
实现不是主要重点。其sh
模式主要是能够在脚本中嵌入或调用(source
)POSIX sh
代码zsh
³最近,@ schily扩展了OpenSolaris Shell(基于SVR4 Shell,基于Bourne Shell)以使其符合POSIX,bosh
但我尚不知道它已在任何系统上使用。随着ksh88
这使得它的第二兼容POSIX的shell基于Bourne外壳的代码
4在较旧的版本中,您也可以使用mksh
POSIX或更高版本的POSIX lksh
。那就是基于pdksh的MirOS(以前的MirBSD)外壳,其本身基于Forsyth外壳(Bourne外壳的另一种实现))