本文主要介绍:什么是 shell、当前系统默认 shell / 可用 shell 列表,以及 sh 与 bash 之间的区别。
在计算机科学中,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)
可以通过以下命令,查看当前使用的 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 解释执行。
通过读取 /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
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 的类型。
与 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 和工具部分的一致实现。
可以在 POSIX 兼容模式下使用 bash,通过设置 -posix
参数在 POSIX 模式下使用,如下所示:
$ bash --posix
另外,我们也可以让 bash 脚本符合 POSIX 标准:
#!/bin/bash
set -o posix
echo Hello, World
set
命令可在脚本中启用选项,在本例中将以 POSIX 模式运行脚本。因此,它使脚本可移植到其他操作系统,如 FreeBSD 和类 UNIX 系统。
bash 提供了很大的灵活性和语法,使其语法很像流行的编程语言。
特性:
使用 <TAB> 键,可以快速完成命令补全操作;
命令历史记录,可以通过使用 <向上> 方向键或<CTRL-R>快速搜索以前执行过的命令;
算术运算,无需任何第三方工具;
关联数组,能够创建具有字符串索引的数组;
键盘快捷键,用于命令行编辑;
自定义功能,可以修改 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 上运行相同的脚本,可能会遇到问题。
从历史背景来看,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 报错依旧可以输出消息;
这两个 shell 都很有用,我们可以在不同的情况下使用它们,具体取决于项目的需求。如果创建的脚本需要在多种 Unix 系统上运行,那么 sh 可能是更好的选择,因为它具有可移植性和兼容性。如果你在 Linux 或 macOS 系统上进行工作,需要额外的功能和语法增强,bash 则是首选 shell。当然,如果我们对可移植性和兼容性有偏执,可以使用 bash 并在纯 POSIX 模式下运行它。
除此之外,如果我们编写一个 sh 脚本,它很可能无需修改即可在 bash 上运行,因为 bash 向后兼容 sh。
sh 是 bash 的前身,它们都可以在所有现代 UNIX/Linux 系统上使用。bash 提供了更舒适且易于使用的体验,而 sh 提供了兼容性、可移植性和标准化语法/行为。