在 Linux 系统中,sh 和 bash 的主要区别在于解释器的功能集与兼容性,日常脚本推荐直接用 bash,涉及系统启动或跨平台兼容时再用 sh,执行前务必确认当前系统/bin/sh 的实际指向。
先说结论:bash 功能更丰富适合日常运维,sh 兼容性更好适合基础环境,两者执行效果取决于系统配置而非命令本身。
- 适合:日常自动化脚本、需要数组或高级特性的场景使用 bash,系统启动脚本或嵌入式环境使用 sh
- 重点看:/bin/sh 是软链接到 bash 还是 dash,Ubuntu 默认为 dash,CentOS 默认为 bash
- 别忽略:直接用 sh 命令运行脚本时会忽略脚本内的 shebang 声明,强制使用 sh 解释器
核心区别与环境确认
sh 通常指 Bourne Shell 或符合 POSIX 标准的 shell,而 bash 是 Bourne Again Shell,是 sh 的超集。在很多 Linux 发行版中,/bin/sh 并不是一个独立的程序,而是一个软链接。例如在 Ubuntu 系统中,/bin/sh 通常链接到 dash,这是一个轻量级且严格遵循 POSIX 标准的 shell,执行速度快但功能较少;而在 CentOS 或 RedHat 系列中,/bin/sh 通常链接到 bash。这意味着同样的 sh 命令在不同系统上调用的底层解释器可能不同,导致脚本行为差异。
查看当前系统 sh 指向哪里,确认解释器环境:
ls -l /bin/sh输出示例(Ubuntu):
lrwxrwxrwx 1 root root 4 Mar 10 2023 /bin/sh -> dash输出示例(CentOS):
lrwxrwxrwx 1 root root 4 Mar 10 2023 /bin/sh -> bash执行方式与解释器优先级
使用 sh script.sh 或 bash script.sh 命令执行时,会强制指定解释器,脚本文件第一行的#!/bin/bash 或#!/bin/sh 声明会被忽略。这解释了为什么有时修改了 shebang 但执行结果不变,因为命令行指定的解释器优先级更高。
指定解释器执行脚本(忽略脚本第一行声明):
sh script.sh
bash script.sh赋予执行权限后直接执行(尊重脚本内的 shebang 声明):
chmod +x script.sh
./script.sh语法兼容性对比
若脚本需要跨发行版运行,建议避免使用 bash 特有语法。以下是常见语法差异:
| 特性 | sh (POSIX/dash) | bash | 兼容性建议 |
|---|---|---|---|
| 数组定义 | 不支持 | 支持 arr=("a" "b") | 跨平台脚本避免使用数组 |
| 条件测试 | 仅支持 [ ] | 支持 [ ] 和 [[ ]] | 统一使用 [ ] |
| 进程替换 | 不支持 <() | 支持 <() | 使用管道或临时文件替代 |
| 函数导出 | 不支持 export -f | 支持 export -f | 避免导出函数 |
报错示例与验证
1. 验证解释器进程:在脚本内部执行以下命令可查看当前进程使用的解释器名称,比 echo $0 更准确:
ps -p $$ -o comm=2. 验证语法支持(数组报错示例):尝试在脚本中定义数组 arr=("a" "b") 并用 sh 执行,若报错则说明当前 sh 环境不支持数组,需改用 bash。
sh 执行数组语法时的典型报错:
sh: 1: arr: not found
# 或
sh: 2: Syntax error: "(" unexpected3. 验证变量作用域:若在脚本中定义变量后希望在当前 shell 使用,需用 source script.sh 或 . script.sh,直接用 sh 或 bash 执行会在子 shell 中运行,变量不会导出到当前环境。
常见工程坑点
1. 系统差异陷阱:在 CentOS 上调试好的 sh 脚本,放到 Ubuntu 上可能报错,因为 Ubuntu 的 sh 是 dash,不支持某些 bash 扩展语法。
2. 执行方式混淆:使用 sh script.sh 执行一个声明为#!/bin/bash 的脚本,会导致 bash 特性失效,脚本报错。
3. 数组语法错误:sh 原生不支持数组,若需兼容 sh,不能用 arr[0] 这种写法,需用字符串模拟或改用 bash。
4. 环境变量丢失:使用 sh 或 bash 命令执行脚本时,脚本内修改的环境变量在脚本结束后会消失,若需持久化需配合 source 使用。