Shell脚本精读 · S13-01 | POSIX sh 与 Bash:语法对照表

模块 :S13 可移植性与规范

篇号 :S13-01 / 42

预计阅读 :50 分钟

主线 :Bash(对照 POSIX sh


文章目录

    • 本篇目标
    • [30 秒速览](#30 秒速览)
    • 正文
      • [1. 先看清 shebang](#1. 先看清 shebang)
      • [2. POSIX sh 与 Bash 关系(够用理解)](#2. POSIX sh 与 Bash 关系(够用理解))
      • [3. 总对照表(语法)](#3. 总对照表(语法))
      • [4. 条件表达式(最常踩坑)](#4. 条件表达式(最常踩坑))
        • [4.1 `[` vs `[[`](#4.1 [ vs [[)
        • [4.2 整数比较](#4.2 整数比较)
        • [4.3 组合条件](#4.3 组合条件)
      • [5. 参数展开](#5. 参数展开)
      • [6. 循环与控制](#6. 循环与控制)
      • [7. 函数与作用域](#7. 函数与作用域)
      • [8. `set` 选项](#8. set 选项)
      • [9. 读脚本:红旗列表](#9. 读脚本:红旗列表)
      • [10. 何时选 sh、何时选 Bash](#10. 何时选 sh、何时选 Bash)
      • [11. 从 Bash 迁到 sh 的替换思路(预览)](#11. 从 Bash 迁到 sh 的替换思路(预览))
      • [12. 与 ShellCheck](#12. 与 ShellCheck)
    • 读脚本检查清单
    • 练习
    • 下一篇预告

本篇目标

建立 POSIX shBash语法对照 :读到 #!/bin/sh 却满篇 [[(( )) 时能判断风险;写脚本时能决定坚持 POSIX 还是明确 Bash 。本篇是对照表 ;编写清单与 command/printfS13-02


30 秒速览

  • POSIX sh :各系统上的 /bin/sh (可能是 dashbash 的 posix 模式 等),语法最小公共子集
  • Bash :扩展多------[[(( )) 、数组、{1..10}pipefail、进程替换等。
  • shebang 与内容要一致#!/bin/sh 里不要写 Bash 专用语法。
  • 可移植 优先:[test$(( ))printf.getopts
  • 本专栏主线是 Bash ;需要 sh 时查本篇 + S13-02。

正文

1. 先看清 shebang

第一行 含义
#!/bin/sh 用系统 sh 解释(不保证是 Bash)
#!/usr/bin/env bash 明确要 Bash(专栏推荐)
#!/bin/bash Bash,路径写死(部分系统无此路径)

读脚本第一问:第一行承诺的运行时,是否支持下文里的 Bash 语法?

bash 复制代码
#!/bin/sh
if [[ -f "$f" ]]; then    # 错:[[ 不是 POSIX

常见情况:作者本机 /bin/sh 指向 bash ,脚本在 dash / Alpine busybox sh 上直接报错。


2. POSIX sh 与 Bash 关系(够用理解)

  • POSIX:标准文档规定 shell 语法子集。
  • 实现 :Linux 上 sh 常为 dash (Debian/Ubuntu)或 bash --posix;macOS 曾长期不同。
  • Bash :超集;bash script.sh 可跑 Bash 语法;sh script.sh 只能跑 POSIX(加实现少量扩展)。

专栏策略 :教学用 Bash;交付若要求 sh,按本篇改写法。


3. 总对照表(语法)

特性 POSIX sh Bash 专栏
条件 if [ ] S05-01
[[ ]] S05-03
正则 =~ [[ ]] S05-03
模式 == *.log [[ ]] S05-03
算术测试 (( )) S05-04
[ "$n" -eq 10 ] S05-01
let 部分 S05-04
function f() ❌(f() 可以) S08-01
local S08-02
数组 arr=( ) S03-04
${arr[@]} S03-04
${var:0:5} 子串 S03-02
${var:-def} 部分(POSIX 有子集) S03-02
for i in {1..10} S07-01
for (( )) S07-01
select S08-04
getopts S08-04
source ❌(用 . ✅ 同 . S08-03
$(cmd) S09-03
进程替换 <( ) S09-04
set -o pipefail S01-04、S09-02
PIPESTATUS S09-02
&> 重定向 S09-01
here-string <<< S09-01
[[&& --- S05-03
echo -e 不可移植 常用 printf S13-02
read -r S07-02
trap EXIT 部分 S11-01
flock 非 POSIX 命令 常见 S11-02
timeout 非 POSIX 命令 GNU S11-02

4. 条件表达式(最常踩坑)

4.1 [ vs [[
bash 复制代码
# POSIX
if [ "$a" = "$b" ]; then
if [ -f "$file" ]; then

# Bash only
if [[ "$a" == "$b" ]]; then
if [[ "$f" == *.log ]]; then
4.2 整数比较
bash 复制代码
# POSIX
[ "$n" -eq 10 ]

# Bash(脚本内常用,但 sh 不行)
(( n >= 10 ))
4.3 组合条件
bash 复制代码
# POSIX:两个 [ 或 -a(不推荐 -a)
[ "$a" = "x" ] && [ "$b" = "y" ]

# Bash
[[ "$a" == "x" && "$b" == "y" ]]

5. 参数展开

写法 POSIX sh Bash
$1 "$@"
${var:-def}
${var:=def}
${#var}
${var#prefix}
${var/pat/rep}
数组 "${a[@]}"

#!/bin/sh 时避免 S03-02 里 Bash 专有展开;S13-02 给替代写法。


6. 循环与控制

bash 复制代码
# POSIX
for f in "$@"; do
while [ "$n" -lt 10 ]; do
  n=$(( n + 1 ))
done

# Bash only
for i in {1..10}; do
for (( i=0; i<10; i++ )); do

break / continue:POSIX 均有。


7. 函数与作用域

bash 复制代码
# POSIX 函数
myfunc() {
  echo "$1"
}

# Bash 扩展
myfunc() {
  local x=1
  declare -i n=0
}

export -f:Bash,非 POSIX。


8. set 选项

选项 POSIX sh Bash
set -e
set -u 部分
set -o pipefail
set -x

#!/bin/sh + set -euo pipefail :在 dash-u 通常可用pipefail 不可用 (ShellCheck SC3043)。


9. 读脚本:红旗列表

见到 #!/bin/sh (或 dash)却出现:

  • [[ (( )) {1..10}
  • source (应用 .
  • 数组、${var//x/y}
  • <( ) &>
  • select

要么 shebang 错了,要么脚本在部分系统会挂 。应改为 #!/usr/bin/env bash 或改写成 POSIX(S13-02)。

见到 #!/usr/bin/env bash:可合理使用专栏全部 Bash 特性。


10. 何时选 sh、何时选 Bash

POSIX sh Bash
嵌入式/极简 rootfs 开发机、CI、团队统一 Bash
明确要求 dash 兼容 需要 数组、[[、pipefail
sh 调用的极小片段 复杂逻辑、运维工具(专栏默认)

不要假设「sh 就是 bash」。


11. 从 Bash 迁到 sh 的替换思路(预览)

Bash POSIX 倾向
[[ -f f ]] [ -f f ]
(( $# < 1 )) [ "$#" -lt 1 ]
[[ $x == *.log ]] case $x in *.log)
${s#pre} sed/expr(笨但可移植)
source f . f
pipefail 拆开管道或显式查 $?

细节与 command/printfS13-02


12. 与 ShellCheck

bash 复制代码
shellcheck -s sh script.sh    # 按 POSIX 扫
shellcheck -s bash script.sh  # 按 Bash 扫

shebang 与 -s 一致。见 S12-02


读脚本检查清单

  • 第一行 shebang 与文内语法是否一致?
  • #!/bin/sh 下是否误用 [[、数组、pipefail
  • 需要 模式匹配 时,sh 是否改用 case
  • 整数比较是否用 -eq 而非 (( ))(在 sh 脚本里)?
  • 是否用 printf 代替 echo -e(S13-02)?

练习

判断题

  1. #!/bin/sh 保证脚本在所有 Unix 上由 Bash 执行。
  2. [[ 是 Bash 扩展,不是 POSIX。
  3. getopts 可在 POSIX sh 脚本中使用。
  4. set -o pipefail 在所有 /bin/sh 实现上都可用。
  5. 读脚本时 shebang 与语法冲突应优先信语法还是信 shebang?------应让它们一致。

参考答案

  1. 错。
  2. 对。
  3. 对。
  4. 错。
  5. 应一致;冲突时按更严格的 sh 理解或改 shebang。

改错题

下面脚本声称兼容 sh,请指出 Bash 专有写法:

bash 复制代码
#!/bin/sh
set -euo pipefail
files=( "$@" )
[[ ${#files[@]} -lt 1 ]] && exit 2
source ./lib.sh
for i in {1..3}; do
  [[ "$i" =~ ^[0-9]+$ ]] && run "$i"
done

参考答案

  • 数组 files=( )${#files[@]}
  • [[=~、模式
  • pipefail(dash sh 不行)
  • source.
  • {1..10}
    应改为 #!/usr/bin/env bash 或逐项 POSIX 化(S13-02)。

对照题

将下列 Bash 改为 POSIX [ / test 风格(不要求可运行,表达即可):

  1. [[ -f "$f" && -r "$f" ]]
  2. (( $# >= 1 ))
  3. [[ "$x" == *.log ]]

参考答案

  1. [ -f "$f" ] && [ -r "$f" ]
  2. [ "$#" -ge 1 ]
  3. case "$x" in *.log) ... ;; esac[ -f "$x" ] 等按语义改写

下一篇预告

S13-02 :《可移植脚本编写清单与 command/printf》--- 实战 checklist、command -v、避免 echo 陷阱,完成 S13 模块。

相关推荐
阿拉斯攀登1 小时前
平台设备驱动:platform bus 与设备树
linux·嵌入式硬件·嵌入式·linux驱动·字符设备驱动
阿拉斯攀登2 小时前
并发与同步:自旋锁、信号量、互斥锁
linux·网络·嵌入式硬件·linux驱动·字符设备驱动
网络小白不怕黑2 小时前
10.邮件服务器搭建并脚本实现监控httpd状态
linux·运维·服务器
Carlos_Xu3 小时前
Linux基础-基础命令
linux
风曦Kisaki3 小时前
# Linux实战笔记-HIS项目实战Day01:版本控制与Git基础
linux·笔记·git
jsons14 小时前
rocky8内网离线批量补丁(你之前搭建的架构,多台服务器首选,无订阅)
linux·运维·服务器
阿拉斯攀登4 小时前
SPI 设备驱动开发
linux·驱动开发·嵌入式硬件·linux内核·嵌入式·linux驱动·spi
阿拉斯攀登4 小时前
定时器与延时:内核定时器、hrtimer 与延时函数
linux·嵌入式硬件·linux内核·嵌入式·linux驱动
zhou135284822675 小时前
Windows 配置 WSL (Ubuntu) 环境完整指南
linux·windows·ubuntu