尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

Linux命令-sh(Bourne Shell 与 POSIX 模式 Shell)

Linux命令-sh(Bourne Shell 与 POSIX 模式 Shell)
📅 发布时间:2026/7/28 16:23:39

Linux命令-sh(Bourne Shell 与 POSIX 模式 Shell)

    • 🔰 简介
    • 📖 语法
    • ⚙️ 选项
    • 💡 实战示例
      • 示例 1:sh -c 字符串执行(最常用)
      • 示例 2:sh 调试 - x / v / n
      • 示例 3:sh vs bash 关键差异
      • 示例 4:脚本可移植性 - shebang 选择
      • 示例 5:登录 sh 与交互 sh
      • 示例 6:sh 在系统脚本中的角色
      • 示例 7:sh -c 的安全与转义
      • 示例 8:写真正的 sh 脚本(POSIX 严格)
    • ⚠️ 注意事项
    • 📝 总结
    • 📚 相关命令

快速参考sh通常指代/bin/sh——Linux 上的POSIX 标准 Shell 解释器。在历史上指 Bourne Shell(Stephen Bourne 于 1977 年在贝尔实验室开发),在现代 Linux 中/bin/sh通常是一个符号链接,指向bash(CentOS/Ubuntu 桌面)或dash(Debian/Ubuntu 服务器)。理解sh与bash的差异是写可移植脚本的关键。

核心差异:Bash 提供很多扩展功能(数组、[[ ]]、<<<here-string 等),sh必须保持POSIX 兼容,更严格。


🔰 简介

项目说明
命令全称Bourne Shell(POSIX shell)
常见实现bash --posix、dash、busybox sh、ash、ksh
标准POSIX 1003.1(Shell & Utilities)
Debian 系/bin/sh→/bin/dash(更轻、更快、严格 POSIX)
RHEL/CentOS/bin/sh→/bin/bash(bash 模拟 POSIX)
Ubuntu 桌面/bin/sh→/bin/dash
启动文件/etc/profile、~/.profile(不读~/.bashrc)
Shebang 写法#!/bin/sh通用、严格
#!/bin/bash扩展、便捷
启动速度dash 极快,bash 较慢

不同发行版的 /bin/sh 实现:

发行版/bin/sh →特点
CentOS 7bashbash 启动时检测 SHELL 变量,进入 POSIX 模式
CentOS 8+bash同上
Ubuntu 16.04+dash严格 POSIX,更快,更小(150KB vs 1MB)
Debian 10+dash同上
Alpine Linuxash极简,常用于 Docker 镜像
FreeBSDtcshBSD 系默认

为什么 Debian 把 sh 换成 dash?

  1. 性能:dash 启动约 10ms,bash 约 50-100ms,对启动脚本意义重大
  2. 内存:dash 仅占 150KB,bash 占 1MB+
  3. POSIX 严格性:dash 不支持 bash 特有语法,强制脚本可移植
  4. 脚本加速:系统启动时跑成百上千的 sh 脚本,dash 提速明显

📖 语法

sh[选项]脚本文件[参数...]sh-c命令字符串

⚙️ 选项

选项说明
-c CMD从字符串执行命令(最常用:sh -c 'cmd',适合复杂命令)
-i交互模式(提示符$)
-l/--login登录 shell(读/etc/profile、~/.profile)
-s从标准输入读取命令
-x调试模式:每条命令执行前先打印(+前缀),再执行
-v详细模式:读到的每行原样打印(执行前)
-e遇错立即退出(errexit)
-n仅语法检查,不执行
-u未定义变量报错(nounset)
-o OPTION设置选项(同set)
-a导出所有变量
-f关闭通配符
-h哈希命令位置(默认)
-k命令参数全部当作赋值
-t执行一条命令后退出
-D/--dump-strings打印所有""字符串(不执行)
--选项结束标志
--help/--version帮助/版本

💡 实战示例

示例 1:sh -c 字符串执行(最常用)

# ========== 1. 单条命令 ==========$sh-c'echo Hello from sh'Hello fromsh# ========== 2. 多条命令(用 ; 或换行) ==========$sh-c'cd /tmp; ls; pwd'file1.txt file2.log /tmp# ========== 3. 复杂逻辑(for/while/if) ==========$sh-c' for i in 1 2 3; do echo "Number: $i" done 'Number:1Number:2Number:3# ========== 4. 管道与重定向 ==========$sh-c'cat /etc/hostname | tr a-z A-Z'WEB01# ========== 5. sudo + sh ==========$sudosh-c'echo "root ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers'# 双引号内是 sudo 执行的命令# ========== 6. ssh 远程执行 ==========$sshuser@host"sh -c 'ls /tmp'"# 等价$sshuser@host'ls /tmp'# 复杂命令推荐 -c# ========== 7. 嵌入到 find/xargs ==========$find.-name"*.sh"-execsh-c'echo "脚本: $0"'{}\;脚本: ./a.sh 脚本: ./b.sh

示例 2:sh 调试 - x / v / n

# ========== 1. -x 调试模式(最常用) ==========$catdemo.sh#!/bin/shname="Alice"echo"Hello,$name"ls/nonexistent2>/dev/null $sh-xdemo.sh +name=Alice +echo'Hello, Alice'Hello, Alice +ls/nonexistent# 不存在的文件无输出# 关键:`+` 行的就是**实际执行**的命令# 常用于:定位"脚本卡在哪里"# ========== 2. -v 详细模式 ==========$sh-vdemo.sh#!/bin/shname="Alice"+name=Aliceecho"Hello,$name"+echo'Hello, Alice'Hello, Alicels/nonexistent2>/dev/null +ls/nonexistent# 先打印**源代码**行(无 +),再执行(带 +)# ========== 3. -n 仅语法检查(不执行) ==========$catsyntax_error.sh#!/bin/shif[$x==1]# 缺 thenecho"x is 1"fi$sh-nsyntax_error.sh syntax_error.sh: line3: syntax error: unexpected end offile# 退出码 2$echo$?2# 完整命令(带错误)$catsyntax_ok.sh#!/bin/shforiin123;doecho"$i"done$sh-nsyntax_ok.sh $echo$?0# 无输出 = 语法正确# ========== 4. 组合使用 -n -v -x ==========$sh-nvxscript.sh# 三重输出:源码 → 语法检查 → 执行跟踪# 生产环境一般只用 -n 或 -x

示例 3:sh vs bash 关键差异

# ========== 差异 1:[[ ]] vs [ ] ==========# bash 支持 [[ ]]$bash-c'[[ "abc" == *b* ]] && echo match'match# sh 不支持 [[ ]],必须用 [ ] + 模式匹配$ dash-c'[[ "abc" == *b* ]] && echo match'dash:1:[[: not found# dash 报错$ dash-c'case "abc" in *b*) echo match;; esac'match# dash 用 case 或 [ "$x" = "$y" ](**单个等号**)# ========== 差异 2:数组 ==========# bash 支持数组$bash-c'arr=(a b c); echo ${arr[1]}'b# dash 不支持数组$ dash-c'arr=(a b c); echo ${arr[1]}'dash:2: Bad substitution# 用 set 替代$ dash-c'set -- a b c; echo $2'b# ========== 差异 3:函数定义 ==========# bash 两种写法都行$bash-c'function foo() { echo hi; } ; foo'hi# dash 仅 function 关键字或 () 均可$ dash-c'foo() { echo hi; } ; foo'hi# ========== 差异 4:here-string <<< ==========# bash 支持$bash-c'cat <<< "hello"'hello# dash 不支持$ dash-c'cat <<< "hello"'# 无输出(here-string 被忽略)# 改用 echo + pipe$ dash-c'echo "hello" | cat'hello# ========== 差异 5:$RANDOM、$SECONDS ==========# bash 特有$bash-c'echo $RANDOM'20315$ dash-c'echo $RANDOM'$RANDOM# dash 输出字面量# ========== 差异 6:花括号扩展 ==========# bash 支持$bash-c'echo {1..5}'12345$ dash-c'echo {1..5}'{1..5}# 字面输出# 改用 seq$ dash-c'seq 1 5'12345

示例 4:脚本可移植性 - shebang 选择

# ========== 选择建议 ==========# 场景 1:写给**任何 Unix** 跑的脚本(最严格)#!/bin/sh# 优点:POSIX 100% 兼容,Bash/Dash/Ksh/Busybox sh 都能跑# 缺点:少很多便利语法# 适用:运维基础脚本、init 脚本、系统级脚本# 场景 2:写给**现代 Linux** 的便利脚本#!/bin/bash# 优点:能用 [[ ]]、数组、关联数组、<<<# 缺点:不能跑到 FreeBSD 默认 sh# 适用:开发脚本、桌面脚本、CI 脚本# 场景 3:明确"用 dash"#!/bin/dash# 强制 dash,可移植性同 /bin/sh 但启动更快# 场景 4:明确"用 bash"#!/usr/bin/env bash# 推荐写法:在 PATH 找 bash,跨环境更稳

实际脚本示例:

# ========== 可移植脚本(sh) ==========$cat/opt/scripts/portable.sh#!/bin/sh# 适用于所有 POSIX shell# 严格 set 选项set-eu# 错就退出 + 未定义变量报错name="${1:-anonymous}"echo"Hello,$name"# 数组用 set 模拟set-- apple banana cherryecho"第二个水果:$2"# for 循环forfin/etc/*.conf;doecho"配置文件:$f"done# if 用单个 =(POSIX 严格)if["$name"="root"];thenecho"管理员"elseecho"普通用户"fi
# ========== Bash-only 脚本 ==========$cat/opt/scripts/bash_only.sh#!/bin/bash# 用 [[ ]] 比较if[["$name"=="root"]];thenecho"管理员"fi# 数组arr=(a b c)echo"${arr[1]}"# here-stringgrep"pattern"<<<"$text"# 关联数组declare-Auser_age user_age[alice]=30echo"${user_age[alice]}"# 字符串切片str="hello world"echo"${str:6:5}"# world# 进程替换diff<(lsdir1)<(lsdir2)

示例 5:登录 sh 与交互 sh

# ========== 交互 sh(输入 sh 后进入) ==========$sh-i$echo$0sh# 当前 shell 是 sh$echo$SHELL/bin/bash# 注意:$SHELL 是登录 shell(用户的默认),$0 是当前实际 shell$sh-il# -l 登录模式,读 /etc/profile 和 ~/.profile$echo$PS1$# sh 的默认提示符# 不读 ~/.bashrc$ls.bashrc .profile .bashrc .profile# 实际只读 .profile# ========== 指定用户登录 ==========$sudo-i# 等价 sudo su -# 触发登录 shell$sh$echo$0sh# ========== 修改用户的登录 shell ==========$ chsh-s/bin/dash alice# 把 alice 的默认 shell 改为 dash# 下次登录 alice 时$sshalice@host $echo$0-dash# dash 启动(- 是登录标记)

示例 6:sh 在系统脚本中的角色

# ========== 1. 系统启动脚本都用 sh ==========$ls/etc/init.d/*|head-3/etc/init.d/NetworkManager /etc/init.d/README /etc/init.d/abrtd $head-1/etc/init.d/NetworkManager#!/bin/sh# 全部用 /bin/sh# ========== 2. 包管理钩子 ==========$ls/etc/dhcp/dhclient-exit-hooks.d/ $head-1/etc/dhcp/dhclient-exit-hooks.d/debug#!/bin/sh# ========== 3. Cron 默认 shell ==========$cat/etc/crontabSHELL=/bin/sh# cron 任务用 sh 执行# ========== 4. systemd 服务 ExecStart 默认可执行文件 ==========$cat/etc/systemd/system/myapp.service[Service]ExecStart=/bin/sh-c"exec /opt/myapp/bin/server"# 用 sh -c 包装复杂命令# ========== 5. 用户 crontab 任务可显式指定 ==========$crontab-e*/5 * * * * /bin/sh /opt/scripts/backup.sh# 显式指定 sh 避免环境差异

示例 7:sh -c 的安全与转义

# ========== 1. 嵌套 sh -c ==========$sh-c'sh -c "echo nested"'nested# ========== 2. 引号转义 ==========$sh-c'echo "Double quotes"'Double quotes# 内部双引号会被 sh -c 的命令字符串识别# 复杂场景$sh-c"echo '$(date)'"2024年1月15日 星期一14:30:00 CST# 外部是双引号 → $() 会被**当前 shell** 解释# 想要 sh -c 内解释 $()$sh-c'echo "$(date)"'2024年1月15日 星期一14:30:00 CST# 内部单引号 → 内部 sh 解释 $()# ========== 3. 性能对比 ==========# 启动速度(单位:ms)$timedash-c'true'real 0m0.002s# 2ms$timebash-c'true'real 0m0.015s# 15ms# 对 1000 个 sh -c 调用:# dash:2 秒# bash:15 秒# 这是 Debian 改用 dash 的核心理由# ========== 4. 函数内调用 sh -c ==========my_func(){localresult=$(sh-c"echo$1")echo"Result:$result"}# 注意:$1 是外层 shell 解释# 想要 sh -c 内部解释:改用 'echo "$0"'

示例 8:写真正的 sh 脚本(POSIX 严格)

$cat/opt/scripts/posix_strict.sh#!/bin/sh# 严格 POSIX 脚本 - 跨 Unix 兼容# 1. 严格模式set-eu# -e: 任何命令失败立即退出# -u: 使用未定义变量报错# (可加 -o pipefail 但 POSIX 不保证)# 2. 变量赋值(无空格)name="Alice"# 或name=Alice# 没有空格就能省略引号# 3. 命令替换(POSIX 用 ` `,不是 $())date1=`date+%F`date2=$(date+%F)# $() 是 POSIX 标准,更推荐# 4. 条件判断([ = 单等号,POSIX 严格)if["$name"="Alice"];thenecho"Match"fi# 5. for 循环(不依赖 bash 扩展)forfin*.txt;do[-e"$f"]||continue# 处理空目录echo"File:$f"done# 6. while 循环n=0while["$n"-lt5];doecho"n =$n"n=$((n+1))# POSIX 算术done# 7. 退出码exit_code=$?if["$exit_code"-ne0];thenecho"Failed with code:$exit_code"exit"$exit_code"fi# 8. 函数my_log(){level=$1shiftecho"[$(date'+%F %T')] [$level]$*">&2}my_log"INFO""Application started"# 9. 错误处理(trap)cleanup(){echo"Cleaning up..."rm-f/tmp/myapp.lock}trapcleanup EXIT INTTERM# 10. 读文件whileIFS=read-rline;doecho"Line:$line"done</etc/hostname
# 测试可移植性$ dash /opt/scripts/posix_strict.sh $bash--posix/opt/scripts/posix_strict.sh $ busyboxsh/opt/scripts/posix_strict.sh# 三者都能跑 = 真正可移植

⚠️ 注意事项

1. /bin/sh 不一定指向同一程序
Debian/Ubuntu 系指向dash,CentOS/RHEL 系指向bash。脚本可移植必须用 POSIX 语法。

2.sh -x调试会暴露变量

$secret="mypassword"$sh-xscript.sh +secret=mypassword# ⚠️ 密码会显示

调试敏感脚本前先脱敏。

3.sh与bash启动文件不同

  • sh:/etc/profile、~/.profile
  • bash:/etc/profile、~/.bash_profile、~/.bashrc
    在 sh 登录时,~/.bashrc 不会被读。

4. -e 选项的边界

set-efalse# 立即退出echo"never prints"

但if false; then不触发(条件命令不算错)。
与set -o pipefail配合防止管道错失。

5. dash 的 “echo -e” 不支持

$ dash-c'echo -e "a\nb"'-ea b# 把 -e 当字面量

dash 的echo是内建,BSD 风格。改用printf:

$ dash-c'printf "a\nb\n"'a b

6.set -u与$@冲突

set-uecho"$@"# 没参数会报错

正确写法:

echo"${@:-}"# 没参数时用空字符串

7. sh -c ‘多行’ 的换行处理

$sh-c'echo a; echo b'a b $sh-c"echo a echo b"aechob# 字面输出,因为外层双引号未执行 sh 解析换行

复杂多行用 heredoc 传给 sh。

8. shebang 的查找路径
#!/bin/sh是绝对路径;#!/usr/bin/env sh用PATH 查找。后者更可移植(Mac 默认没/bin/sh,但有/usr/bin/env)。

9.sh收到的 HUP 信号
父 shell 退出时,子 sh 会继承 HUP。
nohup sh script.sh &免疫 HUP。

**10. dash 与 bash 的R A N D O M ∗ ∗ d a s h 无 ‘ RANDOM** dash 无 `RANDOM∗∗dash无‘RANDOM,$RANDOM` 字面输出。生产脚本别用这个变量。


📝 总结

sh是 POSIX 标准的 Shell,是 Linux 系统脚本的"通用语"。本节要点:

  • 核心概念:/bin/sh是符号链接,Debian 系指dash,RHEL 系指bash兼容模式
  • 关键选项:
    • sh -c 'cmd'(字符串执行)
    • sh -x script(调试)
    • sh -n script(语法检查)
    • sh -l(登录模式)
  • POSIX 严格:
    • [ "$x" = "$y" ](单等号)
    • 用case或[ ]不用[[ ]]
    • 用set --模拟数组
    • 避免<<<、扩展{1..5}、bash 特有变量
  • 写脚本选择:
    • 系统级 / 跨 Unix:#!/bin/sh
    • 现代 Linux 便利:#!/usr/bin/env bash
  • 调试三件套:-x(执行跟踪)→-n(语法检查)→-v(详细输出)

最终建议:写新脚本,如果只是内部工具,#!/bin/bash即可;写给运维/系统/嵌入式,用#!/bin/sh+ 严格 POSIX 语法;不确定,先shellcheck script.sh(静态分析工具)检查兼容性。


📚 相关命令

命令用途
bashBourne-Again Shell(扩展最多的 sh)
dashDebian Almquist Shell(POSIX 严格)
ashAlmquist Shell(Busybox 嵌入式)
kshKorn Shell(商业传统)
zshZ Shell(macOS 默认)
fishFriendly Shell(用户友好)
csh/tcshC Shell(BSD)
busybox sh嵌入式 Linux 最小 shell
shellcheckShell 脚本静态分析(强烈推荐)
setshell 内置:设置/取消选项
env执行命令并可设置环境变量
exec替换当前进程
source/.当前 shell 读取并执行(不同 sh 行为可能差异)

相关新闻

  • 耐根穿刺型高分子异型片自粘土工布生产企业推荐指南(2026 招投标完整版) - 排水板厂家
  • 杭州管道疏通避坑指南 2026年临平区业主真实推荐 - 余生黄金回收
  • 物联网设备安全:SE050与PIC18F4525硬件集成方案

最新新闻

  • QQ影音2026版安装与优化全指南
  • 嘎嘎降AI和PaperPass哪个降AI更稳:2026年降AI达标率完整对比测试
  • HR与算法工程师必须协同解决的简历筛选困局(2024最新Bias审计框架首次公开)
  • AI生成视频质量翻倍的5个隐藏参数设置:一线团队绝不外传的调优清单
  • Agent 开发避坑合集:工具调用、记忆管理与多 Agent 通信的实战雷区
  • 九章云极Alaya Token完成Kimi K3适配,全球首个开源3T级模型入驻Token工厂

日新闻

  • 力旷智能:伺服驱动系统在制药收瓶设备中的应用解析
  • 2026 网安入门避坑指南,零基础如何避开无效学习直接上手实战
  • 揭秘CFC项目:如何通过手机摄像头实现850kbps无网络文件传输

周新闻

  • 大连理工大学与东京大学联手打造的“主动型AI助手“
  • 170.2026年国家级科研瓶颈:超精密单点金刚石切削(SPDT)光学表面生成
  • SongBloom:革命性歌曲生成框架深度解析——如何通过交织自回归与扩散模型创作完整音乐

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号