HOWTO · Linux

Sh 和 Bash 的区别

本教程解释了什么是 shell,了解当前正在使用的 shell,检查所有可用 shell 的列表以及 sh 和 bash 之间的区别。

本页内容

Shell 是一种命令解释器。若要识别终端中当前运行的 Shell 进程,请检查该进程;若要查看账户配置的登录 Shell,请检查账户记录。系统的 /etc/shells 文件列出被接受为有效登录 Shell 的程序。编写可移植的 POSIX 风格脚本时使用 sh;需要额外功能时则使用 Bash。

什么是 Shell?

Shell 会读取命令,并协调操作系统执行这些命令。交互式 Shell 接收来自终端的命令;脚本文件则可以包含交由解释器运行的命令。Linux 系统可能提供多种 Shell,例如 Bash、Dash 或其他兼容 POSIX 的实现。你当前正在使用的 Shell、账户配置的 Shell,以及某个脚本使用的解释器彼此相关,但它们是不同的信息。

如何查找当前运行的 Shell

在 Linux 上运行 ps -p "$$" -o comm=,即可检查当前的 Shell 进程。参数 $$ 会展开为当前 Shell 的进程 ID,而 ps 会报告该进程的命令名称。这能识别正在运行的进程,但不一定能说明账户登录时会启动哪个 Shell。从其他 Shell、终端或脚本启动的进程,可能与配置的登录 Shell 不同。

/etc/passwd 中的账户记录保存的是配置的登录 Shell,而不是实时运行的进程。若要查询当前账户,可运行 getent passwd "$USER";该命令会查询系统账户数据库并输出账户记录。以冒号分隔的最后一个字段就是配置的 Shell 路径。它可能与当前运行的 Shell 进程不同。系统账户服务和环境配置也会影响会话的启动方式,因此若要确认“现在正在运行什么”,应检查进程。

如何查找可用的 Shell

读取 /etc/shells,例如运行 cat /etc/shells,即可查看系统列为有效登录 Shell 的路径。文件内容因系统而异。它并不完整列出机器上安装的所有 Shell 二进制文件:已安装的程序可能未列入其中,列出的路径也可能由符号链接管理。请用它检查某个 Shell 是否符合登录 Shell 的条件;不要据此断定列出的程序都正在运行,或所有已安装的 Shell 都包含在内。

sh 命令及其用途

sh 是命令语言解释器的传统名称。在可移植的 Shell 脚本中,sh 通常表示使用 POSIX Shell 语言编写脚本,使其能在兼容的实现中运行。POSIX 规定了通用行为,但 /bin/sh 这个路径所指向的实现取决于操作系统和发行版。它可能指向 Dash、Bash 或其他 Shell;请先检查自己的系统,不要假设它指向某一种实现。

脚本的第一行称为 shebang,它指定将脚本作为可执行文件启动时使用的解释器。例如,#!/bin/sh 会请求使用 /bin/sh 处的解释器,但无法保证该路径具体选择哪种实现。也可以在命令行中明确将脚本传给 sh。若脚本是为 sh 编写的,请避免使用仅 Bash 支持的语法;若目标是可移植性,请使用 POSIX 定义的结构。

运行以下示例:

本节中的代码以及显示的标签或输出仍为英文。

printf 'Hello, shell!\n'
Hello, shell!

这条独立命令会打印随附运行时证据中记录的输出。

Bash 及其用途

Bash(Bourne Again SHell)是一种广泛使用的 Shell,提供了可移植 sh 脚本之外的功能,包括数组、[[ ... ]] 测试和进程替换。若脚本使用这些扩展,应在 shebang 中指定 Bash,例如 #!/bin/bash,并使用 Bash 运行脚本。Bash 在 Linux 上很常见,但并非每个 Linux 系统的默认 Shell。

Bash 也可以启用 POSIX 模式。可以用 bash --posix 启动 Bash,或在 Bash 脚本中通过 set -o posix 启用该模式。这会使 Bash 的行为更趋近 POSIX 要求;但它不会把 Bash 变成另一种 sh 实现,也不会让所有 Bash 专用脚本都具备可移植性。若可移植性很重要,请使用 POSIX Shell 语言编写,并在目标系统的 Shell 中测试。