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


53

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

是否有理由宁愿使用/bin/shover /bin/bash,因为bash在十年前的许多Linux和BSD机器上,它普遍存在并且通常是默认的吗?


23
/bin/sh如果您不使用特定bash功能,则可以很好地使用它。有一天,您可能必须在未安装脚本的系统上使用其中一个脚本(远程服务器,嵌入式计算机...)
Mathieu 2015年

1
通常,您应该避免问一些问题,这些问题可以根据观点来回答自己(这是我认为可以回答这个问题的唯一可能方式-但这只是我的观点
mikeserv

9
我认为,可以通过指向至少两个在过去几年中处理此事的组织,并回顾其历史和结果,而无需单打独斗地回答这个问题。附带大量进一步的阅读资料,即可启动。☺
JdeBP

3
@JulesMazur ...the answers so far are fairly subjective...根据定义,“主观”陈述实质上是基于观点的。/bin/bash仅在明确需要bash时使用。作为开发人员40多年了,很久以前bash,除了测试时,我几乎从没有明确需要它。(我也努力避免shell扩展,但是我的大多数脚本都是分发的。)网上的许多脚本也应该广泛使用。
user2338816

2
@ user2338816我不好,我的意思是目标。感谢您的观点!
2015年

Answers:


83
  1. 有些系统默认情况下不运送bash(例如FreeBSD)。
  2. 即使已安装bash,它也可能不在中/bin
  3. 大多数简单的脚本不需要bash。
  4. 使用POSIX shell更可移植,脚本可以在多种系统上运行。

17
另一个原因:/ bin / sh通常比bash快,或者至少加载更快(由于更小)。
derobert 2015年

5
@derobert,/bin/sh就是如果它不是更快的bash,还有像OS / X或RHEL其中一些系统/bin/shbash
斯特凡Chazelas

1
否。某些操作系统将其链接,因为bash向后兼容。
Sobrique

7
相当多的脚本认为/bin/sh/bin/bash。Ubuntu从bash切换到dash打破了所有这些。
atamanroman

19
@atamanroman:这些脚本最初是不正确的,#!/bin/bash如果需要Bash ,就应该使用它们(这没什么问题!)。更改大部分是在Debian上游完成的。它改善了用户体验,对系统启动时间产生了可观的影响。它还对安全性产生了积极影响,请参阅“ Shellshock”。
Dietrich Epp

28

Linux(与Debian有关:Ubuntu,Mint等)中的大多数系统脚本都编写为以更快的破折号运行,破折号是这些系统中的默认/ bin / sh。原因是双重的:

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

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

Bash确实是用户的默认外壳程序,因为它功能更强大,并且具有更多的元素来简化编码。sh在Mac OS中,它也是默认值(从/ bin / sh链接的一个)。但是,bash使用链接名称of sh进行调用会使它以与posix兼容的外壳开始。


2
较有限的外壳程序中可用的工具集数量有限,因此很难编写代码(请避免对此进行任何狂热的战争)。这就是为什么某些用户喜欢zsh的原因,zsh提供的工具比bash还要多。我更喜欢Bash,因为两者之间的平衡。

4
@RobertL,存在于ksh中并为bash所采用的许多功能之所以存在,是因为它们极大地简化了编写健壮且正确的脚本的过程。例如,如果没有各种各样的添加项就可以安全地进行间接分配和评估,则可以使用eval,从而带来安全隐患;同样,在没有内置正则表达式支持的情况下,即使在一行内,也可能需要使用外部命令进行匹配(等等
。– Charles Duffy 2015年

1
@RuiFRibeiro,在Debian中没有静态链接。Dash受到更多限制,但主要限于交互功能(没有完成功能等),因此脚本运行更快。
Jan Hudec 2015年

21

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

除此之外,确实有充分的理由使用Bourne Again shell之外的其他东西来解释shell脚本。这些原因促使Ubuntu和Debian的大型项目在过去的几年中消除了Bashisms,并使许多shell脚本通过系统初始化运行(System 5中有很多 Shell脚本rc),并且软件包安装/删除使用了Debian Almquist外壳,而不是Bourne Again外壳。

简而言之:Bourne Again shell本身就充满了交互式功能,对于符合POSIX的shell脚本而言,它并不是最快的shell解释器。因此,如果可以使自己的shell脚本符合POSIX,并使用更轻量级的程序(例如Debian Almquist shell)对其进行解释,则系统的性能将更好。(最后,Debian必须对Almquist shell进行些微调整,以增加对几个非POSIX 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的。早在世纪之交之前,我编写并发布了一种命令行解释器,该解释器具有“交互式”和“非交互式”两种风格,解释了doco中的这种区别,并注意到COMSPECOS2_SHELL环境变量之间的区别。同样,在Debian的System V中删除Bashism的讨论rc和软件包安装/删除脚本的历史可以追溯到1990年代。

进一步阅读


2
“最后,Debian必须对Almquist shell进行些微调整,以增加对几个非POSIX shell结构的支持,这些结构太深,太广泛地嵌入并且太有用了以至于无法摆脱。” —您在哪个链接中有关于此的信息?听起来很有趣。:)
通配符

3
恕我直言,绩效只是促使人们同意变化的动力。进行更改的最初主要原因是bash不断破坏向后兼容性。我个人必须在职业生涯中至少修复3次bash问题,因为该脚本可以在bash的一个版本中工作,而在另一个bash版本中却失败(通常在操作系统升级后发生)。Dash不仅是一个稍快的解释器。就行为而言,它也更加稳定。
slebetman 2015年

我想知道Schily Bourne Shell手册页中的注释(请参见schilytools.sourceforge.net/bosh.html)是否适合使人们了解如何编写可移植脚本(仅取决于Bourne Shell features1989年)。我所做的是提到旧的Bourne Shells中没有的所有增强功能。顺便说一句:我也想知道一些破折号的bashisms。
2015年

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

这意味着#!/bin/bash除非确认我的脚本中没有巴希姆,否则我总是在我的shebang中使用。

通过将shebang设置为#!/bin/sh您,您可以保证该脚本将适用于的所有实现sh

这比说脚本可以与bash配合使用要大得多。

这是一个脚本示例,根据sh系统使用的实现,脚本的行为可能不正确:

#!/bin/sh
n=1
a=$((++n))
echo $n

使用bash脚本时将打印:

2

使用dash脚本时将打印:

1

如果我想使用#!/bin/sh我该怎么办?

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

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


6
“编写自己的脚本时,应将shebang指向您所测试过的最普通的东西。...通过将shebang设置为#!/ bin / sh,您可以保证脚本将适用于sh的所有实现”。 优秀的点。+1,您让我重新考虑了将来如何写我的伴奏。谢谢!:)
通配符

2
好吧,不是;的所有实现/bin/sh。只是POSIX兼容的。
Blacklight Shining 2015年

4

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

/bin/sh是一个唯一的脚本解释器,可用于所有自称Unix的东西。但是,在大量的旧系统上,/bin/sh相关的实用程序甚至都不符合POSIX.1-1996“外壳和实用程序”规范,更不用说更现代的了。符合标准的工具是可选的附加组件,可以安装在/usr/xpg4此类位置或非显而易见的位置。1 与使用POSIX Shell语言编写脚本相比,使用可移植子外壳语言编写脚本更加乏味且容易出错。(configure如果您不相信我,请通读Autoconf生成的脚本。只需进行设置就足以说服您。)

但是,如果可以假定安装了其他任何脚本解释器(例如Bash),则可以假定安装了用于更好脚本语言的解释器。例如,Perl 比Bash 可能可用。

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

1例如,Solaris 10和更早版本的原始Bourne shell随附为/bin/sh。得知Solaris 11将其更新为ksh93。


3
您将使用哪种语言编写脚本来引导系统?还是在SOHO路由器内部(有限的嵌入式系统)?还是在Android中?在所有这些情况下,都可以使用shell。Perl不行。

1
您的答案中与Solaris相关的部分存在一些错误。在Solaris 10岁以上,/bin/sh不是 POSIX.1-1996但实际上预POSIX语法原始的Bourne shell。#!/bin/sh对于在这些版本中运行的脚本,这非常糟糕。将使用Solaris上的可移植脚本,#!/usr/xpg4/bin/sh而在其他OS上则不会非常可移植。在最新的Solaris上,Oracle Solaris 11于2011年首次发布,它/bin/shksh93符合最新POSIX规范的现代版本,并具有许多现代扩展。
jlliagre

1
@BinaryZebra:“外壳”将可用,是的。但是bash不一定是shell(特别是大多数SOHO路由器使用的ash是busybox附带的外壳),我倾向于zwol是正确的,因为perl比bash更普遍。
Ben Voigt

1
@BenVoigt我对这句话“编写shell脚本的唯一剩余理由”发表评论。仍然有一些实例需要外壳来执行某些任务(不是全部)。这些都是我脑海中的例子。OTOH在具有足够内存(几乎是当今标准中的所有标准)和足够功能的系统中,安装Perl(或Python或....)非常简单快捷。但是,我不主张任何特定的外壳。在我的评论中,您从哪里读到的?

2
完全不同意您的高瞻远瞩和虚幻的说法,即“如果bash可以的话,那么一种更好的语言也应该如此,因此您永远不要编写任何bash代码。” 另外,正如@sixtyfootersdude指出的那样,除非已测试脚本可以与任何POSIX shell配合使用,否则应始终使用。#!/bin/bash
2015年

0

您实际上应该使用

#! /bin/env sh

要么

#! /bin/env bash

这样,您就可以通过将它们安装在该系统上的方式来调用它们。

为了超级安全(例如在单用户重新启动的情况下),请sh使用bash


6
这个答案the advantage of #!/usr/bin/env python is that it will use whatever python executable appears first in the user's $PATH. The disadvantage of #!/usr/bin/env python is that it will use whatever python executable appears first in the user's $PATH.这可能也适用于shbash
2015年

12
不,您不应#!/bin/env在可移植脚本中使用任何内容。假设/bin/sh存在并且是可运行的,与POSIX兼容的外壳是完全合理的。另一方面,我的系统都没有/bin/env
Blacklight Shining

也很好。
Jules

1
@Blacklight发光假定在中使用POSIX兼容外壳绝对是错误的/bin/sh。POSIX不需要它,而是定义其他规则以在POSIX认证平台上获得POSIX兼容环境。
schily

4
/usr/bin/env并非普遍可用...
vonbrand 2015年
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.