sh 和 bash 之间的区别

在编写 shell 程序时,我们经常使用/bin/sh/bin/bash 。我通常使用bash ,但是我不知道它们之间有什么区别。

bashsh之间的主要区别是什么?

在使用bashsh编程时,我们需要注意什么?

答案

什么是嘘

sh (或 Shell 命令语言)是POSIX 标准描述的一种编程语言。它具有许多实现( ksh88dash ,...)。 bash也可以视为sh的实现(请参见下文)。

因为sh是规范而不是实现,所以/bin/sh是到大多数 POSIX 系统上实际实现的符号链接(或硬链接)。

什么是 bash

bash最初是一种与sh兼容的实现(尽管它比 POSIX 标准早了几年),但是随着时间的流逝,它获得了许多扩展。这些扩展中的许多扩展可能会更改有效 POSIX Shell 脚本的行为,因此bash本身不是有效的 POSIX Shell。相反,它是 POSIX Shell 语言的方言。

bash支持--posix开关,这使其更符合 POSIX。如果以sh调用,它也会尝试模仿 POSIX。

sh = 重击?

长期以来, /bin/sh在大多数 GNU / Linux 系统上都指向/bin/bash 。结果,几乎可以忽略两者之间的区别了。但是这种情况最近开始改变。

/bin/sh不指向/bin/bash (在某些情况下甚至可能不存在/bin/bash )的系统的一些流行示例是:

  1. 现代 Debian 和 Ubuntu 系统,其符号链接shdash默认;
  2. Busybox ,通常在 Linux 系统启动期间作为initramfs一部分运行。它使用ash shell 实现。
  3. BSD,通常是任何非 Linux 系统。 OpenBSD 使用pdksh ,它是 Korn shell 的后代。 FreeBSD 的sh是原始 UNIX Bourne shell 的后代。 Solaris 具有自己的sh ,长期以来它不符合 POSIX。 Heirloom 项目提供了免费的实现。

您如何找出/bin/sh指向系统上的内容?

复杂之处在于/bin/sh可能是符号链接或硬链接。如果它是符号链接,则一种可解决的便携式方法是:

% file -h /bin/sh
/bin/sh: symbolic link to bash

如果是硬链接,请尝试

% find -L /bin -samefile /bin/sh
/bin/sh
/bin/bash

实际上, -L标志同时覆盖了符号链接和硬链接,但是这种方法的缺点是它不可移植-samefile 不需要 find支持-samefile选项,尽管GNU findFreeBSD find 都支持它。

社 bang 线

最终,由您决定要使用哪一个,即编写 “shebang” 行。

例如

#!/bin/sh

将使用sh (以及发生的任何事件),

#!/bin/bash

如果可用,将使用/bin/bash如果不可用,则失败并显示错误消息)。当然,您也可以指定其他实现,例如

#!/bin/dash

使用哪一个

对于我自己的脚本,出于以下原因,我更喜欢使用sh

  • 它是标准化的
  • 它更容易学习
  • 它可以跨 POSIX 系统移植 - 即使它们碰巧没有bash ,也要求它们具有sh

使用bash也有优势。它的功能使编程更加方便,并且类似于其他现代编程语言中的编程。这些包括范围局部变量和数组之类的东西。 Plain sh是一种非常简约的编程语言。

shhttp : //man.cx/sh
bashhttp//man.cx/bash

TL; DRbashsh的超集,具有更优雅的语法和更多功能。在几乎所有情况下,使用 bash shebang 行都是安全的,因为它在现代平台上非常普遍。

注意:在某些环境中, sh bash 。检查sh --version

对于试图使用sh人来说,这个问题经常被提名为规范问题,并且惊讶地发现它与bash行为不同。这是常见误解和陷阱的快速清单。

首先,您应该了解期望。

  • 如果使用sh scriptname运行脚本,或者使用scriptname运行脚本,并且在shebang行中包含#!/bin/sh ,则应该期望 POSIX sh行为。
  • 如果您使用bash scriptname运行脚本,或者使用scriptname运行脚本,并且在 shebang 行中包含#!/bin/bash (或本地等效项),则应该期待 Bash 的行为。

通常,首选解决方案是使用正确的 shebang 并通过仅键入脚本名称(可能使用相对路径或完整路径 )来运行脚本。除了正确的 shebang 之外,这还要求脚本文件具有执行权限( chmod a+x scriptname )。

那么,它们实际上有何不同?

《 Bash 参考手册》的一部分试图列举这些差异,但是一些常见的混淆源包括

  • [[sh不可用(仅[更笨重且受限制)。
  • sh没有数组。
  • 一些 Bash 关键字(例如localsourcefunctionshoptletdeclareselect不可移植到sh 。 (某些sh实现支持例如local 。)
  • Bash 具有许多 C 样式的语法扩展,例如三参数for((i=0;i<=3;i++))循环, +=增量分配等。 $'string\nwith\tC\aescapes'功能是暂时被 POSIX 接受 (这意味着它现在可在 Bash 中使用,但尚不支持仅符合当前 POSIX 规范的sh on 系统,并且可能会在一段时间内不支持)。
  • Bash 支持<<<'here strings'
  • Bash 具有*.{png,jpg}{0..12}大括号扩展。
  • ~是指$HOME只在击(更通常~username来的主目录username )。 这在 POSIX 中,但是在某些 POSIX 之前的/bin/sh实现中可能会丢失。
  • Bash 具有<(cmd)>(cmd)进程替换。
  • Bash 具有 Csh 样式的便捷重定向别名,例如&| 2>&1 |&>用于> ... 2>&1
  • Bash 支持带有<>重定向的协同进程。
  • Bash 具有丰富的扩展非标准参数扩展集,例如${substring:1:2}${variable/pattern/replacement} ,大小写转换等。
  • Bash 大大扩展了 Shell 算术的功能(尽管仍然没有浮点支持)。有一种过时的旧式$[expression]语法,但是应替换为 POSIX 算术$((expression))语法。 (不过,某些旧的 POSIX sh实现可能不支持此功能。)
  • $RANDOM$SECONDS$PIPESTATUS[@]$FUNCNAME等魔术变量是 Bash 扩展。
  • 不可移植的语法差异,例如export variable=value[ "x" == "y" ]export variable应与变量赋值分开, [ ... ]可移植字符串比较使用单个等号)。
  • 许多,仅 Bash 的扩展用于启用或禁用可选行为并公开 Shell 的内部状态。
  • 用于交互使用的许多便利功能,但这并不影响脚本行为。

请记住,这是一个简短的清单。有关完整的信息,请参考参考手册;有关许多好的解决方法,请参见http://mywiki.wooledge.org/Bashism 。和 / 或尝试http://shellcheck.net/ ,它警告了许多仅 Bash 功能。

一个常见的错误是使用#!/bin/bash shebang 行,但是仍然使用sh scriptname脚本名实际运行该脚本。这基本上会禁用任何仅 Bash 的功能,因此会出现语法错误,例如,尝试使用数组。 (shebang 行在语法上是注释,因此在这种情况下将其忽略。)

不幸的是,当您尝试将这些构造作为sh调用时,Bash 不会发出警告。它也不会完全禁用所有仅 Bash 的功能,因此,通过以sh身份调用 Bash 来运行 Bash 并不是检查脚本是否可正确移植到ash / dash / POSIX shHeirloom sh变体的好方法

UNIX.COM 发布

外壳功能

下表列出了我认为会让您选择一个外壳而不是另一个外壳的大多数功能。它不打算作为权威列表,也不包括每个可能的 shell 的每个可能的功能。仅当功能在操作系统随附的版本中,或者可以从标准发行版直接编译得到时,才认为该功能在外壳程序中。特别是,下面指定的 C Shell 在 SUNOS 4. * 上可用,现在许多供应商都提供 tcsh 或自己的增强型 C Shell(它们并不总是很明显地表明他们在交付 tcsh。

码:

sh   csh  ksh  bash tcsh zsh  rc   es
Job control                          N    Y    Y    Y    Y    Y    N    N
Aliases                              N    Y    Y    Y    Y    Y    N    N
Shell functions                      Y(1) N    Y    Y    N    Y    Y    Y
"Sensible" Input/Output redirection  Y    N    Y    Y    N    Y    Y    Y
Directory stack                      N    Y    Y    Y    Y    Y    F    F
Command history                      N    Y    Y    Y    Y    Y    L    L
Command line editing                 N    N    Y    Y    Y    Y    L    L
Vi Command line editing              N    N    Y    Y    Y(3) Y    L    L
Emacs Command line editing           N    N    Y    Y    Y    Y    L    L
Rebindable Command line editing      N    N    N    Y    Y    Y    L    L
User name look up                    N    Y    Y    Y    Y    Y    L    L
Login/Logout watching                N    N    N    N    Y    Y    F    F
Filename completion                  N    Y(1) Y    Y    Y    Y    L    L
Username completion                  N    Y(2) Y    Y    Y    Y    L    L
Hostname completion                  N    Y(2) Y    Y    Y    Y    L    L
History completion                   N    N    N    Y    Y    Y    L    L
Fully programmable Completion        N    N    N    N    Y    Y    N    N
Mh Mailbox completion                N    N    N    N(4) N(6) N(6) N    N
Co Processes                         N    N    Y    N    N    Y    N    N
Builtin artithmetic evaluation       N    Y    Y    Y    Y    Y    N    N
Can follow symbolic links invisibly  N    N    Y    Y    Y    Y    N    N
Periodic command execution           N    N    N    N    Y    Y    N    N
Custom Prompt (easily)               N    N    Y    Y    Y    Y    Y    Y
Sun Keyboard Hack                    N    N    N    N    N    Y    N    N
Spelling Correction                  N    N    N    N    Y    Y    N    N
Process Substitution                 N    N    N    Y(2) N    Y    Y    Y
Underlying Syntax                    sh   csh  sh   sh   csh  sh   rc   rc
Freely Available                     N    N    N(5) Y    Y    Y    Y    Y
Checks Mailbox                       N    Y    Y    Y    Y    Y    F    F
Tty Sanity Checking                  N    N    N    N    Y    Y    N    N
Can cope with large argument lists   Y    N    Y    Y    Y    Y    Y    Y
Has non-interactive startup file     N    Y    Y(7) Y(7) Y    Y    N    N
Has non-login startup file           N    Y    Y(7) Y    Y    Y    N    N
Can avoid user startup files         N    Y    N    Y    N    Y    Y    Y
Can specify startup file             N    N    Y    Y    N    N    N    N
Low level command redefinition       N    N    N    N    N    N    N    Y
Has anonymous functions              N    N    N    N    N    N    Y    Y
List Variables                       N    Y    Y    N    Y    Y    Y    Y
Full signal trap handling            Y    N    Y    Y    N    Y    Y    Y
File no clobber ability              N    Y    Y    Y    Y    Y    N    F
Local variables                      N    N    Y    Y    N    Y    Y    Y
Lexically scoped variables           N    N    N    N    N    N    N    Y
Exceptions                           N    N    N    N    N    N    N    Y

上表的关键字。

可以使用此 shell 完成功能。

N 功能不存在于外壳中。

F 功能只能通过使用 shell 函数机制来完成。

L 必须将 readline 库链接到外壳中才能启用此功能。

上表说明

1. This feature was not in the original version, but has since become
   almost standard.
2. This feature is fairly new and so is often not found on many
   versions of the shell, it is gradually making its way into
   standard distribution.
3. The Vi emulation of this shell is thought by many to be
   incomplete.
4. This feature is not standard but unofficial patches exist to
   perform this.
5. A version called 'pdksh' is freely available, but does not have
   the full functionality of the AT&T version.
6. This can be done via the shells programmable completion mechanism.
7. Only by specifying a file via the ENV environment variable.

Shell是用户和 OS 之间的接口,用于访问操作系统的服务。它可以是 GUI 或 CLI(命令行界面)。

sh (Bourne sh ell)是一个 Shell 命令行解释器,用于类似 Unix / Unix 的操作系统。它提供了一些内置命令。在脚本语言中,我们将解释器表示为#!/bin/sh 。它是 bash(自由 / 开放),kash(非自由)之类的其他 shell 支持最广泛的一种。

(B ourne 增益 地狱)是一个外壳更换对于 Bourne 壳。 Bash 是 sh 的超集。 Bash 支持 sh。 POSIX 是一组定义 POSIX 兼容系统应如何工作的标准。 Bash 实际上不是 POSIX 兼容的外壳。在脚本语言中,我们将解释器表示为#!/bin/bash

比喻:

  • Shell 就像一个接口或规范或 API。
  • sh 是实现 Shell 接口的类。
  • Bash 是 sh 的子类。

在此处输入图片说明

终奌站

  • 打开窗口的程序
  • xterm,rxvt,konsole,kvt,gnome-terminal,nxterm 和 eterm。

贝壳

  • 是在终端上运行的程序
  • Shell 既是命令解释器又是编程语言
  • 壳牌只是执行命令的宏处理器。
  • 宏处理器意味着将文本和符号扩展以创建更大的表达式的功能。

相对于重击

SH

  • (贝壳)
  • 是特定的外壳
  • 命令解释器和编程语言
  • BASH 的前身

重击

  • (Bourne-Again SHell)
  • 是特定的外壳
  • 命令解释器和编程语言
  • 具有 sh 功能及更多
  • SH 的继任者
  • BASH 是默认的 SHELL

参考资料:

外壳 gnu.org:

根本上说外壳程序只是执行命令的宏处理器 。术语宏处理器是指将文本和符号扩展以创建更大的表达式的功能。

Unix shell 既是命令解释器又是编程语言。作为命令解释器,shell 为丰富的 GNU 实用程序集提供了用户界面。编程语言功能允许组合这些实用程序。包含命令的文件可以创建,也可以成为命令本身。这些新命令与 / bin 等目录中的系统命令具有相同的状态,从而允许用户或组建立自定义环境以自动化其常见任务。

外壳可以交互使用或非交互使用。在交互模式下,它们接受键盘输入的输入。当以非交互方式执行时,shell 执行从文件读取的命令。

Shell 允许同步和异步执行 GNU 命令。在接受更多输入之前,shell 等待同步命令完成。异步命令继续与外壳程序并行执行,同时读取并执行其他命令。重定向结构允许对这些命令的输入和输出进行细粒度的控制。而且,外壳程序允许控制命令环境的内容。

Shell 还提供了一小组内置命令(builtins),这些命令实现了无法或不方便通过单独的实用程序获得的功能例如,cd,break,continue 和 exec 不能在 Shell 外部实现,因为它们直接操纵 Shell 本身。历史记录,getopts,kill 或 pwd 内置程序等可以在单独的实用程序中实现,但是用作内置命令更方便。后续各节将介绍所有的 shell 内建函数。

尽管执行命令是必不可少的,但是大多数 Shell 的功能(和复杂性)都归功于它们的嵌入式编程语言。像任何高级语言一样,shell 提供变量,流控制构造,引用和函数。

Shell 提供了专门为交互使用而设计的功能,而不是扩展编程语言。这些交互式功能包括作业控制,命令行编辑,命令历史记录和别名。这些功能中的每一个都在本手册中进行了描述。

BASH gnu.org:

Bash 是 GNU 操作系统的外壳程序或命令语言解释器。该名称是'Bourne-Again SHell' 的首字母缩写,它是 Stephen Bourne 的双关语,Stephen Bourne 是当前 Unix shell sh 的直接祖先的作者,该版本出现在 Unix 的第七版 Bell Labs Research 版本中。

Bash 在很大程度上与 sh 兼容,并结合了 Korn shell ksh 和 C shell csh 的有用功能。它旨在成为 IEEE POSIX 规范(IEEE 标准 1003.1)的 IEEE POSIX 外壳和工具部分的一致实现。它提供了相对于 sh 的功能改进,可用于交互和编程。

虽然 GNU 操作系统提供了其他 shell,包括 csh 版本,但Bash 是默认的 shell 。像其他 GNU 软件一样,Bash 具有很好的可移植性。目前,它几乎可以在 Unix 的每个版本和其他一些操作系统上运行 - MS-DOS,OS / 2 和 Windows 平台具有独立支持的端口。

其他答案通常指出 Bash 与 POSIX Shell 标准之间的区别。但是,在编写可移植的 shell 脚本并使用 Bash 语法时,非常典型的 bashism 列表和相应的纯 POSIX 解决方案非常方便。当 Ubuntu 从 Bash 切换为 Dash 作为默认系统外壳时,已经编译了此类列表,可以在以下位置找到: https : //wiki.ubuntu.com/DashAsBinSh

而且,有一个很棒的工具叫做checkbashisms ,它可以检查脚本中的 bashisms,并且在您要确保脚本可移植时很方便。

/bin/sh可能会也可能不会调用与/bin/bash相同的程序。

sh 至少支持POSIX 所需的功能(假设实现正确)。它也可能支持扩展。

bash (“Bourne Again Shell”)实现了 sh 以及 bash 特定的扩展所必需的功能。完整的扩展程序集太长,无法在此处描述,并且随新版本的发布而变化。差异记录在 bash 手册中。输入info bash并阅读 “Bash 功能” 部分(当前版本中的第 6 部分),或者在线阅读当前文档

bash 和 sh 是两个不同的 shell。 bash 基本上是 sh,具有更多功能和更好的语法。大多数命令的工作原理是相同的,但它们是不同的。Bash(bash)是许多可用的(至今仍是最常用的)Unix shell 之一。 Bash 代表 “Bourne Again SHell”,并且是对原始 Bourne shell(sh)的替换 / 改进。

Shell 脚本是在任何 Shell 中编写脚本,而 Bash 脚本是专门为 Bash 编写脚本。但是,实际上,除非有问题的 shell 不是 Bash,否则 “shell 脚本” 和 “bash 脚本” 通常可以互换使用。

话虽如此,您应该在大多数系统上意识到 / bin / sh 是符号链接,并且不会调用 sh。在 Ubuntu 中,/ bin / sh 用于链接到 bash,这是 Linux 发行版上的典型行为,但现在已更改为链接到另一个称为 dash 的 shell。我会使用 bash,因为这几乎是标准的(或者至少从我的经验来看是最常见的)。实际上,当 bash 脚本将使用#!/ bin / sh 时会出现问题,因为脚本创建者认为链接不一定是 bash。

它们几乎相同,但是bash具有更多功能 sh (或多或少)是bash的较旧子集。

sh通常是指原始的Bourne shell ,它早于bashBourne *again* shell ),创建于 1977 年。但是,在实践中,最好将其视为与 POSIX 兼容的高度交叉兼容的 shell。 1992 年的标准。

#!/bin/sh开头或使用sh shell 的脚本通常这样做是为了向后兼容。任何 unix / linux 操作系统都将具有sh shell。在 Ubuntu 上, sh经常调用dash而在 MacOS 上,它是bash的特殊 POSIX 版本。对于标准兼容的行为,速度或向后兼容性,这些外壳可能是首选。

bash比原始sh更新,添加了更多功能,并力求与sh向后兼容。从理论上讲, sh程序应以bash运行。 bash在几乎所有的 linux / unix 机器上都可用,并且通常默认情况下使用 - 值得注意的是 MacOS 在 Catalina(10.15)之前默认为zsh 。 FreeBSD 在默认情况下没有安装bash