cover_image

Linux 中 sh 和 bash 有什么区别?

JPZhang 滑翔的纸飞机
2024年04月08日 00:00

1. 写在前面

本文主要介绍:什么是 shell、当前系统默认 shell / 可用 shell 列表,以及 sh 与 bash 之间的区别。

2. 什么是 shell?

在计算机科学中,shell 俗称壳(用来区别于核),是指 “为使用者提供操作界面” 的软件(command interpreter,命令解析器)。它类似于 DOS 下的 COMMAND.COM 和后来的 cmd.exe 。它接收用户命令,然后调用相应的应用程序。

bash shell 是 Linux 中的默认 shell,通常也是所有用户首先熟悉的 shell。除此之外,也可以使用许多其他 shell 工具,例如 sh、zsh、ksh、csh 和 tcsh等。

通过示例理解 shell 执行流程,如,打开系统终端并运行以下命令:

root@jpzhang:~# date
-------------------------------------------------------------------------------------
2024年 04月 07日 星期日 11:52:04 CST

执行流程:

  • 默认 shell 接受命令 “date”,解释并运行 date 工具;

  • 在控制台屏幕上打印输出结果;

各种 Unix shell:

图片

第一个 Unix shell 是由肯·汤普逊,仿效 Multics 上的 shell 所实现出来,称为 sh。

Bourne shell兼容

  • Bourne shell(sh)史蒂夫·伯恩在贝尔实验室时编写。1978 年随 Version 7 Unix 首次发布。

    • Almquist shell(ash)

    • Bourne-Again shell(bash)

    • Debian Almquist shell(dash)

    • Korn shell(ksh)David Korn 在贝尔实验室时编写

    • Z shell(zsh)

C shell兼容

  • C shell(csh)比尔·乔伊在加州大学伯克利分校时编写。1979 年随 BSD 首次发布。

    • TENEX C shell(tcsh)

其他

  • fish,第一次发布于2005年。

  • rc shell(rc)九号项目系统的 shell,由 Tom Duff 在贝尔实验室时编写。随后移植回Unix 和其他的操作系统。

    • es shell(es)一个函数式编程的 rc 兼容 shell,编写于二十世纪九十年代中期。

  • scsh(Scheme shell)

2.1 如何查看当前使用的 shell?

可以通过以下命令,查看当前使用的 shell:

root@jpzhang:~# grep $USER /etc/passwd
-------------------------------------------------------------------------------------
root:x:0:0:root:/root:/bin/bash
  • $USER:当前登录的用户;

  • /etc/passwd:存储用户账户信息;

或者:

# 缺点:不能实时反映当前 shell
root@jpzhang:~# echo $shell
-------------------------------------------------------------------------------------
/bin/bash

可以看到默认使用的 shell 是 bash。因此,当我们使用终端时,命令将由 bash 解释执行。

2.2 如何查看当前发行版可以使用的 shell ?

通过读取 /etc/shell 文件,可以列出当前 Linux 发行版上有哪些可用的 shell:

root@jpzhang:~# cat /etc/shells
-------------------------------------------------------------------------------------
# /etc/shells: valid login shells
/bin/sh
/bin/bash
/bin/rbash
/bin/dash
/usr/bin/tmux
/usr/bin/screen

3. 什么是 sh ?

sh 又称 Bourne shell,是一种用于类 UNIX 系统的命令编程语言,由 POSIX(Portable Operating System Interface)标准定义,在大多数 Linux 系统中,它是由原始的 Bourne shell、dash 和 ksh 等程序实现的。

POSIX(Portable Operating System Interface,可移植操作系统接口)是由 IEEE(Institute of Electrical and Electronics Engineers)定义的一组操作系统接口标准。它的目标是为应用程序提供一套与操作系统无关的接口,使得这些应用程序能够在不同的 POSIX 兼容系统上编译和运行。因此,它可以帮助我们通过遵循一系列准则,为多个操作系统开发跨平台软件。

大多数系统都有 /bin/sh 文件,但它是一个符号链接指向 Bourne shell。在 Ubuntu 中,/bin/sh 是指向到 dash shell 的符号链接。我们可以通过运行下面的命令来检查:

root@jpzhang:~# file -h /bin/sh
-------------------------------------------------------------------------------------
/bin/sh: symbolic link to dash

正如所看到的,/bin/sh 是到 dash 的符号链接,后者是 Debian 发行版使用的 POSIX 兼容 shell。在 shell 脚本中,可以将 #!/bin/sh 作为第一行,然后由 dash 执行:

#!/bin/sh

echo Hello, World!

上面的脚本指定 /bin/sh 作为解释器。然而,由于 /bin/sh 指向 dash,dash shell 将作为解释器执行脚本。因此,该脚本可以移植到其他兼容 POSIX 的操作系统上,因为它遵循了 POSIX 标准。

【注意】

大多数 shell 脚本的第一行都是 #!/bin/sh,但需要注意的是,/bin/sh 可能不是指向 Bourne 兼容 shell 的符号链接。有时,脚本作者会假定 /bin/sh 指向 /bin/bash 或 /bin/dash,但实际上有可能并不是这样。因此,在编写和执行脚本之前,最好先检查 /bin/sh 的类型。

4. 什么是 bash?

与 sh 一样,bash(Bourne Again shell)也是一种命令语言处理器和 shell。它是大多数 Linux 发行版默认登录 shell。bash 是 sh 的超集,这意味着 bash 支持 sh 的功能,并在此基础上提供了更多扩展和特性。不过,大多数命令的工作方式与 sh 类似。

自 bash 发布以来,它已成为 Linux 操作系统 shell。但是,bash 不是符合 POSIX 标准的 shell,而是 POSIX shell 语言的方言。bash 旨在成为 IEEE POSIX 规范(IEEE 标准 1003.1)的 IEEE POSIX shell 和工具部分的一致实现。

4.1 如何使 bash 符合 POSIX 标准?

可以在 POSIX 兼容模式下使用 bash,通过设置 -posix 参数在 POSIX 模式下使用,如下所示:

$ bash --posix

另外,我们也可以让 bash 脚本符合 POSIX 标准:

#!/bin/bash

set -o posix
echo Hello, World

set 命令可在脚本中启用选项,在本例中将以 POSIX 模式运行脚本。因此,它使脚本可移植到其他操作系统,如 FreeBSD 和类 UNIX 系统。

4.2 bash 特性

bash 提供了很大的灵活性和语法,使其语法很像流行的编程语言。

特性:

  • 使用 <TAB> 键,可以快速完成命令补全操作;

  • 命令历史记录,可以通过使用 <向上> 方向键或<CTRL-R>快速搜索以前执行过的命令;

  • 算术运算,无需任何第三方工具;

  • 关联数组,能够创建具有字符串索引的数组;

  • 键盘快捷键,用于命令行编辑;

  • 自定义功能,可以修改 bash 提供的默认显示方式;

4.3 编写 bash 脚本

指定 #!/bin/bash 作为第一行,如下:

#!/bin/bash

# Determine if the number is odd or even
read -p "Enter a number: " number
if [ `expr $number % 2` -eq 0 ]; then
echo "${number} is even"
else
echo "${number} is odd"
fi

保存脚本文件并使其可执行:

root@jpzhang:~/linux# chmod +x bash_test.sh
root@jpzhang:~/linux# ./bash_test.sh
-------------------------------------------------------------------------------------
Enter a number: 12
12 is even

该脚本可在大多数 Linux 发行版上运行,但如果在 FreeBSD 上运行相同的脚本,可能会遇到问题。

5. sh 与 bash 的区别

从历史背景来看,sh 和 bash 的相似之处多于差异,主要区别在于:

  • 默认 shell

    当前大多数现代系统中,bash 是默认 shell;/bin/sh 往往是指向具体实现的符号链接;

  • 二进制文件

    root@jpzhang:~/linux# which sh
    -------------------------------------------------------------------------------------
    /bin/sh
    root@jpzhang:~/linux# which bash
    -------------------------------------------------------------------------------------
    /bin/bash
  • 特性

    与 sh 相比,bash 提供了更大的灵活性和语法,看起来像现代编程语言;

    如上所述特性:

    使用 <TAB> 键,可以快速完成命令补全操作;
    命令历史记录,可以通过使用<向上>方向键或 <CTRL-R> 快速搜索以前执行过的命令;
    算术运算, 无需任何第三方工具;
    关联数组,能够创建具有字符串索引的数组;
    键盘快捷键, 用于命令行编辑;
    自定义功能,可以修改 bash 提供的默认显示方式;
  • POSIX 合规性

    默认情况下,bash 不符合 POSIX 标准,可以使用命令在 POSIX 兼容模式下运行 bash;sh 遵循 POSIX 规范,提供了更好的可移植性;

  • 执行面

    sh:当某行代码出错时,不继续往下执行;bash:就算出错,也会继续向下执行;

    sh 测试脚本:

    #!/bin/sh

    source .env
    echo "Error message"

    bash 测试脚本:

    #!/bin/bash

    source .env
    echo "Error message"

    执行如下:

    root@jpzhang:~/linux/bash_sh# sh sh_test.sh
    sh_test.sh: 3: sh_test.sh: source: not found
    Error message
    -------------------------------------------------------------------------------------
    root@jpzhang:~/linux/bash_sh# sh bash_test
    sh: 0: Can't open bash_test

    可以看到,sh 报错依旧可以输出消息;

5. 使用哪一种?

这两个 shell 都很有用,我们可以在不同的情况下使用它们,具体取决于项目的需求。如果创建的脚本需要在多种 Unix 系统上运行,那么 sh 可能是更好的选择,因为它具有可移植性和兼容性。如果你在 Linux 或 macOS 系统上进行工作,需要额外的功能和语法增强,bash 则是首选 shell。当然,如果我们对可移植性和兼容性有偏执,可以使用 bash 并在纯 POSIX 模式下运行它。

除此之外,如果我们编写一个 sh 脚本,它很可能无需修改即可在 bash 上运行,因为 bash 向后兼容 sh。

6. 结论

sh 是 bash 的前身,它们都可以在所有现代 UNIX/Linux 系统上使用。bash 提供了更舒适且易于使用的体验,而 sh 提供了兼容性、可移植性和标准化语法/行为。

感谢您花时间阅读文章!

关注公众号不迷路!



继续滑动看下一个
滑翔的纸飞机
向上滑动看下一个