sh 是一个非常基础且重要的命令,理解它对于掌握 Linux/Unix 系统至关重要。

核心概念:sh 是什么?
sh 的全称是 Bourne Shell,由 Stephen Bourne 在 AT&T 的贝尔实验室开发,它是 Unix 系统中最古老、最经典的命令行解释器(Shell)之一。
在现代 Linux 系统中,/bin/sh 通常不是一个真正的 Bourne Shell 程序,而是一个指向另一个兼容 Shell 的符号链接,最常见的情况是,它指向了 bash (Bourne-Again Shell) 或 dash (Debian Almquist Shell)。
- 在 Debian/Ubuntu 系统上:
/bin/sh通常指向dash。dash是一个更轻量、更快速的 Shell,专注于遵循 POSIX 标准,常用于系统启动脚本等对性能要求高的场景。 - 在 CentOS/RHEL/Fedora 系统上:
/bin/sh通常指向bash。
关键点:当你运行 sh 命令时,你其实是在启动一个兼容 Bourne Shell 语法的 Shell 环境,这个环境可能是 bash,也可能是 dash,或者其他兼容的 Shell。
sh 命令的主要用途
sh 命令主要有以下几种用法:

运行 Shell 脚本文件
这是 sh 最常见的用途,它会读取指定的脚本文件,并逐行执行其中的命令。
语法:
sh [选项] 脚本文件名 [参数...]
示例:
假设你有一个名为 hello.sh 的脚本,内容如下:
#!/bin/bash echo "Hello, World!" echo "第一个参数是: $1" echo "脚本的进程ID是: $$"
执行方式:

# 给脚本执行权限(虽然用 sh 执行不一定需要,但这是好习惯) chmod +x hello.sh # 使用 sh 命令执行 $ sh hello.sh Linux
输出:
Hello, World!
第一个参数是: Linux
脚本的进程ID是: 12345 # 这个ID会变化
重要区别:sh script.sh vs ./script.sh
-
sh hello.sh:- 会启动一个新的
sh进程(可能是dash或bash)。 - 这个新进程会读取并执行
hello.sh文件。 - 不会使用
hello.sh文件第一行的shebang(#!/bin/bash) 指定的解释器,它强制使用sh命令指定的 Shell。
- 会启动一个新的
-
./hello.sh:- 首先会检查
hello.sh文件第一行的shebang(#!/bin/bash)。 - 然后启动一个
bash进程来执行这个脚本。 - 需要
hello.sh文件拥有可执行权限 (chmod +x hello.sh)。
- 首先会检查
sh script.sh 是“用 sh 来运行脚本”,而 ./script.sh 是“让脚本自己决定用哪个 Shell 来运行自己”。
交互式 Shell
你也可以直接输入 sh 命令来进入一个交互式的 Shell 环境。
示例:
$ sh $ # 现在你进入了 sh 的命令行环境 $ echo "我在 sh 环境中" 我在 sh 环境中 $ $PATH # 打印环境变量 /usr/local/bin:/usr/bin:/bin $ exit # 退出 sh 环境 exit $ # 你回到了原来的 Shell
这个用法相对较少,因为大多数人更习惯使用功能更强大的 bash(直接输入 bash 或 Enter 键)。
执行单条命令
你可以像使用 bash 或其他 Shell 一样,用 sh 来执行单个命令。
示例:
$ sh -c 'echo "This is a single command"' This is a single command
-c 选项告诉 sh 将后面的字符串作为一个完整的命令来执行,这在编程中非常有用,例如在 C 语言或 Python 中通过 system() 函数调用 Shell 命令时。
常用选项
sh 命令支持一些有用的选项:
| 选项 | 全称 | 描述 |
|---|---|---|
-c |
--command |
从一个字符串中读取并执行命令。 |
-s |
--stdin |
从标准输入读取并执行命令,当没有给出文件名参数时很有用。 |
-v |
--verbose |
在读取输入时,将其内容显示到标准错误输出,用于调试脚本。 |
-x |
--xtrace |
在执行命令之前,将其显示到标准错误输出。这是最常用的调试选项。 |
-n |
--noexec |
只进行语法检查,但不实际执行命令,用于检查脚本是否有语法错误。 |
调试选项示例 (-x)
假设有一个有问题的脚本 debug.sh:
#!/bin/bash for i in 1 2 3 do echo "Processing item $i" # 故意写一个错误的命令 my_command $i done
执行它:
$ sh debug.sh Processing item 1 debug.sh: line 5: my_command: command not found Processing item 2 debug.sh: line 5: my_command: command not found Processing item 3 debug.sh: line 5: my_command: command not found
使用 -x 选项执行,可以看到每一步的执行过程:
$ sh -x debug.sh + for i in 1 2 3 + echo 'Processing item 1' Processing item 1 + my_command 1 debug.sh: line 5: my_command: command not found + for i in 1 2 3 + echo 'Processing item 2' Processing item 2 + my_command 2 debug.sh: line 5: my_command: command not found + for i in 1 2 3 + echo 'Processing item 3' Processing item 3 + my_command 3 debug.sh: line 5: my_command: command not found
号开头的行就是 sh -x 显示的执行步骤,非常有助于定位问题。
sh 与 bash 的关键区别
虽然 sh 通常指向 bash,但当你显式调用 sh 时,脚本会以POSIX 模式运行,这会导致一些行为与 bash 不同。
| 特性 | sh (POSIX 模式) |
bash (默认模式) |
|---|---|---|
| 函数定义 | funcname() { commands; } |
function funcname() { commands; } 或 funcname() { commands; } |
| 数组 | 不支持 | 支持 (my_array=(a b c)) |
[[ ... ]] |
不支持,只能用 [ ... ] 或 test。 |
支持,更强大、更安全(推荐使用)。 |
echo -e |
不支持 -e 解释转义字符。 |
支持 -e 选项。 |
$RANDOM |
没有这个内置变量。 | 有,用于生成随机数。 |
source 命令 |
没有 source,使用 来执行脚本。 |
两者都有,source 更易读。 |
示例:数组
# 在 bash 中可以
$ bash -c 'arr=(a b c); echo ${arr[1]}'
b
# 在 sh 中会报错
$ sh -c 'arr=(a b c); echo ${arr[1]}'
sh: arr=(a b c): bad array substitution
| 方面 | 描述 |
|---|---|
| 身份 | sh 是一个命令,用于启动一个兼容 Bourne Shell 语法的 Shell 环境,在现代 Linux 上,它通常是 bash 或 dash 的一个链接。 |
| 主要用途 | 执行 Shell 脚本 (sh script.sh),强制使用 sh 环境。调试脚本,使用 -x 选项追踪执行流程。执行单条字符串命令 ( sh -c '...')。 |
| 核心原则 | 兼容性。sh 旨在提供最大程度的 POSIX 标准兼容性,而 bash 在此基础上增加了许多更方便、更强大的功能。 |
| 何时使用 | - 当你明确需要一个轻量级、严格遵循标准的 Shell 时。 - 当你运行的系统脚本(如 /etc/init.d/ 下的脚本)指定了 #!/bin/sh 时,应该用 sh 执行。- 当你不确定目标系统上 bash 是否可用,或者需要确保脚本的可移植性时,应该为脚本编写 sh 兼容的语法。 |
对于日常使用,bash 更为流行和强大,但在系统管理、编写需要高度兼容性的脚本时,理解并正确使用 sh 至关重要。
