有什么理由让shebang指向/bin/sh而不是/bin/bash?

Jul*_*les 54 shell bash history shebang

在我见过的大多数 shell 脚本中(除了我自己没有写的脚本),我注意到 shebang 设置为#!/bin/sh. 这在旧脚本上并没有让我感到惊讶,但在相当新的脚本上也是如此。

是否有任何理由宁愿/bin/sh/bin/bash,因为bash几乎是无处不在的,而且往往默认情况下,许多Linux和BSD的机器回去了十多年?

Mar*_*rco 85

  1. 有些系统默认不提供 bash(例如 FreeBSD)。
  2. 即使安装了 bash,它也可能不在/bin.
  3. 大多数简单的脚本不需要 bash。
  4. 使用 POSIX shell 更易于移植,脚本将在更多种类的系统上运行。

  • @atamanroman:首先脚本是不正确的,如果他们想要 Bash,他们应该使用 `#!/bin/bash`(没有错!)。更改主要是在 Debian 的上游完成。它改善了用户体验,对系统启动时间产生了显着影响。它还对安全性产生了积极影响,请参阅“Shellshock”。 (19认同)
  • 另一个原因:通常 /bin/sh 比 bash 快,或者至少加载速度更快(由于更小)。 (17认同)
  • 相当多的脚本假设`/bin/sh` 是`/bin/bash`。Ubuntu 从 _bash_ 切换到 _dash_ 破坏了所有这些。 (8认同)
  • @derobert,如果不是`bash`,`/bin/sh` 会更快,仍然有一些系统如OS/X 或RHEL,其中`/bin/sh` 是`bash`。 (5认同)

小智 28

Linux 中(与 Debian 相关的:Ubuntu、Mint 等)中的大多数系统脚本都编写为在更快的 dash 中运行,这是这些系统中的默认 /bin/sh。原因有两个:

  • 系统的速度。较小的破折号代码加载速度更快,运行速度也更快。为 shell 脚本程序员提供一些(小?)额外的努力(成本)。

  • 安全。拥有多样性的外壳有助于抵御错误。Debian 系统大多不容易受到 shellshock 的影响,因为默认的 shell 没有这样的漏洞。

Bash 确实是用户的默认 shell ,因为它更强大,并且有更多的元素使编码更容易。它也是shMac OS 中的默认设置(从 /bin/sh 链接的那个)。但是,bash使用 的链接名称调用sh使其作为符合 posix 的 shell 启动。

  • @RobertL,在 ksh 中添加并被 bash 采用的许多工具之所以存在,是因为它们大大简化了编写健壮且正确的脚本的过程。没有允许安全执行间接分配和评估的各种添加,例如,您可以使用 `eval` 发现自己,伴随着安全暴露;类似地,如果没有内置的正则表达式支持,即使在单行等中,也可能需要使用外部命令(以严重的性能损失)进行匹配。 (4认同)
  • 一个更简单的 shell 的一组更有限的可用工具使得为其编写代码变得更加困难(请避免对此进行任何狂热的战争)。这就是为什么一些用户喜欢 zsh 的原因,它比 bash 有更多的可用工具。我更喜欢 Bash,因为它是两个极端之间的平衡。 (2认同)

Jde*_*eBP 21

其他人指出,问题的前提,即 Bourne Again shell 是默认的并且无处不在,这是完全错误的。

除此之外,使用 Bourne Again shell 以外的东西来解释 shell 脚本确实有很好的理由。动机Ubuntu的和Debian的大项目,过了若干年后,除去bash化,并让尽可能多的shell脚本的这些原因,在系统初始化运行(这是一个很多与系统5 shell脚本rc)和包安装/拆卸使用的Debian Almquist shell而不是 Bourne Again shell。

简而言之:Bourne Again shell 充满了交互功能,但对于符合 POSIX 的 shell 脚本来说,它并不是最快的 shell 解释器。因此,如果可以使自己的 shell 脚本符合 POSIX 标准,并使用更轻量级的程序(如 Debian Almquist shell)来解释它们,那么系统的性能会更好。(最后,Debian 不得不对 Almquist shell 进行细微的调整,以添加对几个非 POSIX shell 构造的支持,这些构造太深入和广泛嵌入并且太有用而无法摆脱。)

这一切的结果是引导程序性能的重大提升。

所以这里有两种不同的 shell 类需要考虑:

  • 具有所有华丽交互功能的外壳,这些外壳被配置为帐户数据库中用户的交互登录外壳
  • 快速解释大量脚本的shell,被shell脚本程序用作脚本解释器

请注意,将其称为“偏好/bin/sh”过于简单化。Debian 实际上至少有两个目标:

  1. 面对使用 Debian Almquist shell、Z Shell(在 POSIX 模式下)、Bourne Again shell(在 POSIX 模式下)、MirBSD Korn shell 和其他人的管理员/bin/sh,要么……

    1. ...使脚本尽可能可移植,以便切换/bin/sh映射到的内容不会破坏事物;或者

    2. ...使不可移植的脚本明确针对正确的解释器程序,而不是简单地期望/bin/sh映射到它。

  2. 有制作的Debian Almquist外壳的默认映射/bin/sh,而不是Bourne shell的,所以,那些脚本POSIX的符合性(或者,更确切地说,Debian策略手册符合性)更快速地跑了。

当然,一旦进入这一领域,就可以走得更远;如考虑的喜欢的效率的权衡/bin/true,并/usr/bin/clear为shell脚本或编译的程序。但幸运的是,这超出了这个答案的范围。☺

当然,这些都不是新的,甚至也不是特定于 Unix 的。早在世纪之交之前,我编写并发布了一个命令行解释器,它有“交互式”和“非交互式”两种风格,解释了其文档中的这种划分,并指出了环境变量COMSPECOS2_SHELL环境变量之间的区别。同样,关于在 Debian 的 System V 中删除 bashismrc和软件包安装/删除脚本的讨论可以追溯到 1990 年代。

进一步阅读

  • “最后,Debian 不得不对 Almquist shell 进行细微的调整,以添加对几个非 POSIX shell 构造的支持,这些构造太深入和广泛嵌入并且太有用而无法摆脱。” — 你的许多链接中的哪一个有这方面的信息?这听起来很有趣。:) (3认同)
  • 恕我直言,性能只是让人们同意这些变化的动力。更改的最初重要原因是 bash 不断破坏向后兼容性。在我的职业生涯中,我个人不得不至少修复 3 次 bash 问题,因为脚本可以在一个版本的 bash 中运行,但在另一个版本中失败(通常发生在操作系统升级之后)。Dash 不仅仅是一个稍微快一点的解释器。它在行为方面也更加稳定。 (3认同)

six*_*ude 8

有什么理由让shebang指向/bin/sh而不是/bin/bash?

是的。@Marco 的出色回答很好地概括了这一点。

我应该在我的shebang中使用什么?

在编写自己的脚本时,您应该将shebang 指向您测试过的最通用的东西。

在我的系统(Centos 6.6)上,sh符号链接到bash

$ ls -l /bin/sh 
lrwxrwxrwx 1 root root 4 Dec  2  2014 /bin/sh -> bash
Run Code Online (Sandbox Code Playgroud)

这意味着我总是#!/bin/bash在我的 shebang 中使用,除非我已经确认我的脚本中没有 bashim。

通过将 shebang 设置为#!/bin/sh您承诺该脚本将适用于sh.

这是一个比说脚本将与 bash 一起工作更大的承诺。

下面是一个脚本示例,它会根据sh系统使用的实现而行为不正确:

#!/bin/sh
n=1
a=$((++n))
echo $n
Run Code Online (Sandbox Code Playgroud)

使用bash脚本时会打印:

2
Run Code Online (Sandbox Code Playgroud)

使用dash脚本时会打印:

1
Run Code Online (Sandbox Code Playgroud)

如果我想使用#!/bin/sh我需要做什么?

  • 检查脚本checkbashisms- 请注意,这不会找到所有 bashim。它没有在我上面的脚本中找到 bashism
  • 使用另一个sh实现测试脚本。我通常使用 进行测试dash,但是我希望一些 bashisms 或 dashims 仍然可以通过。

DashAsBinSh页面上的Ubuntu的wiki有许多有趣的信息。

  • “在编写自己的脚本时,您应该将 shebang 指向您测试过的最通用的东西....通过将 shebang 设置为 #!/bin/sh,您承诺该脚本将适用于 sh 的所有实现.” *优秀*点。+1,你让我重新思考我将如何为未来写我的shebangs。谢谢!:) (6认同)
  • 好吧,不是 `/bin/sh` 的 _all_ 实现;只是符合 POSIX 的那些。 (2认同)

zwo*_*wol 5

编写 shell 脚本而不是使用更强大且符合人体工程学的语言的脚本的唯一剩余原因是,是否可移植到具有一组未知的已安装软件的遗留系统比任何其他因素都更重要

/bin/sh是唯一一个可用于所有自称 Unix 的脚本解释器。但在大量遗留系统上,/bin/sh相关实用程序甚至不符合 POSIX.1-1996“shell 和实用程序”规范,更不用说更现代的规范了。符合标准的工具是可选的附加组件,安装在/usr/xpg4或某些此类不明显的位置。1 编写可移植子集 shell 语言的脚本比编写 POSIX shell 语言的脚本更加繁琐且容易出错。configure(如果您不相信我,请有时阅读 Autoconf 生成的脚本。仅设置就足以说服您。)

但是,如果您可以假设安装了任何其他脚本解释器(例如 Bash),那么您可以假设安装了更好的脚本语言的解释器。例如,Perl比 Bash容易使用。

因此,您永远不应该编写#! /bin/bash脚本,因为如果可以选择,那么更好的语言也是一种选择。

1例如,Solaris 10 及更早版本将原始 Bourne shell作为/bin/sh. 我得知Solaris 11已将其更新为ksh93。

  • 您将使用哪种语言编写启动系统的脚本?或者在 SOHO 路由器内(有限的嵌入式系统)?或者在安卓系统中?在所有这些情况下都可以使用 shell。Perl 没有。 (3认同)
  • 完全不同意你的固执己见和非事实的说法,即“如果‘bash’可用,那么它就是一种更好的语言,所以你永远不应该编写任何‘bash’代码。” 另外,正如 @sixtyfootersdude 指出的那样,您应该*始终*使用`#!/bin/bash`,除非您已经*测试*您的脚本适用于任何 POSIX shell。 (2认同)