当前位置: 首页 > news >正文

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

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 服务器)。理解shbash的差异是写可移植脚本的关键。

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


🔰 简介

项目说明
命令全称Bourne Shell(POSIX shell)
常见实现bash --posixdashbusybox shashksh
标准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)'"20241月15日 星期一14:30:00 CST# 外部是双引号 → $() 会被**当前 shell** 解释# 想要 sh -c 内解释 $()$sh-c'echo "$(date)"'20241月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.shbash启动文件不同

  • 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 shPATH 查找后者更可移植(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 无 `RANDOMdashRANDOM$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 行为可能差异)
http://www.jsqmd.com/news/1281623/

相关文章:

  • MyBatis注解之一对多关联实战
  • 开源模型本地部署不是“复制粘贴”!资深MLOps工程师拆解7层依赖链:Python环境、CUDA驱动、量化格式、Tokenizer对齐、KV Cache优化…
  • 数据库的相关概念
  • 物联网设备安全芯片选型与SE050应用实践
  • Karpathy四大原则:提升AI编程协作效率的提示词工程方法论
  • 软件测试面试,8年测试老兵竟被面试官10分钟pass,这也太难了吧
  • QQ空间说说备份终极指南:GetQzonehistory轻松保存你的青春记忆
  • 毕业季论文写作AI工具全攻略:从文献挖掘到格式规范
  • 2026湖州膜结构车棚厂家哪家好避坑指南:5个挑选要点,帮你避开80%的坑 - geo88
  • 唤醒游戏记忆:MemcardRex终极PlayStation存档管理指南
  • Webcamoid:模块化多媒体处理框架的技术架构与跨平台实现
  • 【Bug已解决】[Bug]: raise error when setting --pipeline_parallel_size > 3 in ray cluster 解决方案
  • 零基础一键重装系统:从风险认知到安全实操的完整指南
  • 蓄排水板生产厂家推荐指南(2026 招投标完整版) - 排水板厂家
  • Prompt注入→数据反抽→模型窃取:AI应用层泄露三重跳杀链,4小时紧急修复方案已验证
  • 总结:Git常用命令
  • B站视频下载神器:5分钟学会下载大会员4K高清视频和充电专属内容
  • 运维3年,我转行网安了_从连Burp都打不开到挖到第一个漏洞,用了47天
  • 集合(set)的运用代码
  • 如何彻底解锁Wand专业版功能:5种高级策略完全指南
  • 宣扬国学,我朋友这样做
  • 太原晋源区管道疏通避坑指南 2026 本地师傅推荐 - 余生黄金回收
  • Windows原生AI智能体开发:微软执行容器(MXC)与未来开发范式解析
  • 11 | 弹性伸缩与 Serverless:用 HPA 让 AI 服务「峰谷自适应」
  • Nutz简单项目创建
  • 大模型应用开发架构设计与工程实践指南
  • IPBan实战指南:构建企业级服务器安全防护架构
  • QueryExcel终极指南:三分钟搞定上百个Excel文件搜索的免费解决方案
  • 2026 年东莞一站式拆除清运 场地平整 家装拆除选择技巧 - LYL仔仔
  • 图神经网络实战:Node2Vec算法与UMAP可视化全解析