Gok*_*tug 15 shell bash ubuntu shell-script shebang
通常,shell 脚本在脚本文件的第一行包含以下注释:#!/bin/sh. 根据我的研究,这被称为“哈希爆炸”,这是常规评论。此注释通知 Unix 该文件由目录下的 Bourne Shell 执行/bin。
我的问题从那一点开始。直到现在我还没有看到这样的评论#!/bin/bash。它总是#!/bin/sh。但是,Ubuntu 发行版没有 Bourne Shell 程序。他们有 Bourne Again Shell (bash)。
在这一点上,将注释#!/bin/sh放在用 Ubuntu 发行版编写的 shell 脚本中是否正确?
jes*_*e_b 17
#!/bin/sh应该适用于所有 Unix 和类 Unix 发行版。只要您的脚本保持 POSIX 兼容,它通常被认为是最便携的 hashbang。该/bin/sh外壳应该是一个外壳,实现了POSIX标准的外壳,不管实际的外壳是什么,伪装成/bin/sh壳。
#!/bin/sh现在通常只是一个链接,因为不再维护 Bourne shell。在许多 Unix 系统/bin/sh上将是指向/bin/ksh或的链接/bin/ash,在许多基于 RHEL 的 Linux 系统上它将是一个链接/bin/bash,但是在 Ubuntu 和许多基于 Debian 的系统上它是一个链接/bin/dash。所有 shell 在调用时sh都将进入 POSIX 兼容模式。
hashbang 是一个重要的占位符,因为它比其他方法具有更大的可移植性,只要您的脚本严格符合 POSIX(重复强调重要性)。
注意:当bash在 POSIX 模式下调用时,它仍然允许一些非 POSIX 的东西,比如[[、数组等等。这些事情可能会在非bash系统上失败。
Sté*_*las 12
你已经落后了。/bin/sh这些天来几乎不再是 Bourne shell,而且当您使用#! /bin/shshe-bang时,您会遇到问题¹ 。
Bourne shell 是 70 年代后期编写的 shell,它取代了之前的 Thompson shell(也称为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,Bourne shell 的克隆,带有一些 ksh 扩展,因此它符合 POSIX。
今天,所有 POSIX 系统都有一个 shell sh(大多数情况下,但不一定在/bin. 它通常基于 ksh88、ksh93、pdksh、bash、ash 或 zsh²,但不是 Bourne shell,因为 Bourne shell 从来不符合 POSIX 标准³。几个这些炮弹(bash,zsh,yash和一些pdksh衍生物时作为调用使POSIX兼容模式sh,且较少柔顺以其他方式)。
bash(GNU 对 Korn shell 的回答)实际上是唯一被认证为符合 POSIX sh(作为 macOS 认证的一部分)。
当您使用#! /bin/sh -she-bang编写脚本时,您应该使用标准sh语法(如果您想要可移植,还应该使用该脚本中使用的实用程序的标准语法,在解释 shell 时不仅涉及 shell脚本),那么sh使用该标准语法解释器的什么实现都无关紧要(ksh,bash...)。
只要您不使用这些 shell,这些 shell 是否对标准进行了扩展都没有关系。这就像编写 C 代码一样,只要您编写标准 C 代码并且不使用一个编译器(如gcc)或另一个编译器的扩展,您的代码应该可以正常编译,无论编译器实现如何,只要编译器兼容。
在这里,你的#! /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
Run Code Online (Sandbox Code Playgroud)
顺便说一下,Ubuntu/bin/sh不是bash默认的。现在dash,一个基于 NetBSD 的外壳sh,本身基于 Almquist 外壳,除了不支持多字节字符外,它主要符合 POSIX 标准。在Ubuntu和其他基于Debian的系统,你可以选择bash和dash对/bin/sh带dpkg-reconfigure dash)4。shDebian 附带的脚本在两个 shell 中的工作方式应该相同,因为它们是按照 Debian 策略标准(POSIX 标准的超集)编写的。您可能会发现他们还工作确定zsh的sh仿真或bosh(可能不是ksh93,也不yash该没有local内置(由Debian政策而不是POSIX)要求)。
unix.stackexchange.com 范围内的所有系统在sh 某处都有一个 POSIX 。他们中的大多数都有一个/bin/sh(您可能会发现非常罕见的没有/bin目录但您可能并不关心它),并且通常是一个 POSIXsh解释器(在极少数情况下是一个(非标准)Bourne shell )。
但它sh是您可以确保在系统上找到的唯一 shell 解释器可执行文件。对于其他 shell,您可以确定 macOS、Cygwin 和大多数 GNU/Linux 发行版都有bash. SYSV 派生的操作系统(Solaris、AIX...)通常具有 ksh88,可能是 ksh93。OpenBSD、MirOS 都会有 pdksh 的衍生品。macOS 将具有zsh. 但除此之外,将无法保证。不保证是否bash或任何其他 shell 将安装在/bin或其他地方(/usr/local/bin例如,安装时通常会在BSD 上找到)。当然也不保证将安装的 shell 的版本。
请注意,这#! /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
Run Code Online (Sandbox Code Playgroud)
当您使用/bin/sh -代替 时/bin/echo test,内核会执行/bin/sh - ./myscript foo,sh解释存储在其中的内容代码myscript并忽略第一行,因为它是注释(以 开头#)。
¹ 可能今天我们中任何人都会遇到/bin/sh基于 Bourne shell的唯一系统是 Solaris 10。Solaris 是少数几个决定保留 Bourne shell 以实现向后兼容性的 Unices 之一(POSIXsh语言并不完全向后兼容的Bourne shell兼容)和(至少在台式机和全服务器部署)有POSIXsh其他地方(在/usr/xpg4/bin/sh基于ksh88),但改变了Solaris 11的地方/bin/sh,现在是ksh93的。其他的大多已不复存在。
²所述/bin/sh的MacOS / X曾经是zsh,但后来改变到bash。zsh用作 POSIXsh实现并不是主要关注点。它的sh模式主要是能够在脚本中嵌入或调用 ( source) POSIXsh代码zsh
³ 最近,@schily扩展了 OpenSolaris shell(基于 SVR4 shell,基于 Bourne shell)以符合 POSIX 标准,被称为bosh但我不知道它已在任何系统上使用。除此之外ksh88,它是基于 Bourne shell 代码的第二个符合 POSIX 的 shell
4在旧版本中,您还可以使用mksh或其更多的 POSIXlksh化身。那是基于 pdksh 的 MirOS(以前的 MirBSD)shell,它本身基于 Forsyth shell(Bourne shell 的另一个重新实现))
是的,您可以#!/bin/sh在脚本中使用,因为/bin/sh(希望)在此类系统上提供,通常通过某种链接使bash行为(或多或少)像一个sh会。例如,这是一个 Centos7 系统,它链接sh到bash:
-bash-4.2$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Dec 4 16:48 /bin/sh -> bash
-bash-4.2$
Run Code Online (Sandbox Code Playgroud)
#!/bin/bash如果您bash仅为该系统编写脚本并想要使用bash功能,您也可以使用。然而,这样的脚本会受到可移植性问题的影响,例如在 OpenBSD 上,bash只有在管理员不厌其烦地安装它(我没有)然后将它安装到/usr/local/bin/bash,而不是/bin/bash. 严格的 POSIX#!/bin/sh脚本应该更具可移植性。
你问
将注释 #!/bin/sh 放在以 ubuntu 发行版编写的 shell 脚本中是否正确?
答案取决于您在 shell 脚本中编写的内容。
如果您严格使用可移植的 POSIX 兼容脚本,并且不使用任何特定于 bash 的命令,那么您可以使用/bin/sh.
如果您知道您只在装有 bash 的机器上使用该脚本,并且您想使用特定于 bash 的语法,那么您应该使用/bin/bash
如果您想确保脚本可以在各种 unix 机器上运行,那么您应该只使用符合 POSIX 的语法,并且/bin/sh
如果您经常使用另一个 shell(例如ksh、zsh或tcsh),并且想在您的脚本中使用该语法,那么您应该使用适当的解释器(例如/bin/ksh93, /bin/zsh, 或/bin/tcsh)