Linux命令-sh(Bourne Shell 与 POSIX 模式 Shell)
发布时间:2026/7/28 16:03:12
分类:文化教育
浏览:1234
)
Linux命令-shBourne Shell 与 POSIX 模式 Shell 简介 语法⚙️ 选项 实战示例示例 1sh -c 字符串执行最常用示例 2sh 调试 - x / v / n示例 3sh vs bash 关键差异示例 4脚本可移植性 - shebang 选择示例 5登录 sh 与交互 sh示例 6sh 在系统脚本中的角色示例 7sh -c 的安全与转义示例 8写真正的 sh 脚本POSIX 严格⚠️ 注意事项 总结 相关命令快速参考sh通常指代/bin/sh——Linux 上的POSIX 标准 Shell 解释器。在历史上指 Bourne ShellStephen Bourne 于 1977 年在贝尔实验室开发在现代 Linux 中/bin/sh通常是一个符号链接指向bashCentOS/Ubuntu 桌面或dashDebian/Ubuntu 服务器。理解sh与bash的差异是写可移植脚本的关键。核心差异Bash 提供很多扩展功能数组、[[ ]]、here-string 等sh必须保持POSIX 兼容更严格。 简介项目说明命令全称Bourne ShellPOSIX shell常见实现bash --posix、dash、busybox sh、ash、ksh标准POSIX 1003.1Shell UtilitiesDebian 系/bin/sh→/bin/dash更轻、更快、严格 POSIXRHEL/CentOS/bin/sh→/bin/bashbash 模拟 POSIXUbuntu 桌面/bin/sh→/bin/dash启动文件/etc/profile、~/.profile不读~/.bashrcShebang 写法#!/bin/sh通用、严格#!/bin/bash扩展、便捷启动速度dash 极快bash 较慢不同发行版的 /bin/sh 实现发行版/bin/sh →特点CentOS 7bashbash 启动时检测 SHELL 变量进入 POSIX 模式CentOS 8bash同上Ubuntu 16.04dash严格 POSIX更快更小150KB vs 1MBDebian 10dash同上Alpine Linuxash极简常用于 Docker 镜像FreeBSDtcshBSD 系默认为什么 Debian 把 sh 换成 dash性能dash 启动约 10msbash 约 50-100ms对启动脚本意义重大内存dash 仅占 150KBbash 占 1MBPOSIX 严格性dash 不支持 bash 特有语法强制脚本可移植脚本加速系统启动时跑成百上千的 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帮助/版本 实战示例示例 1sh -c 字符串执行最常用# 1. 单条命令 $sh-cecho Hello from shHello fromsh# 2. 多条命令用 ; 或换行 $sh-ccd /tmp; ls; pwdfile1.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-ccat /etc/hostname | tr a-z A-ZWEB01# 5. sudo sh $sudosh-cecho root ALL(ALL) NOPASSWD: ALL /etc/sudoers# 双引号内是 sudo 执行的命令# 6. ssh 远程执行 $sshuserhostsh -c ls /tmp# 等价$sshuserhostls /tmp# 复杂命令推荐 -c# 7. 嵌入到 find/xargs $find.-name*.sh-execsh-cecho 脚本: $0{}\;脚本: ./a.sh 脚本: ./b.sh示例 2sh 调试 - x / v / n# 1. -x 调试模式最常用 $catdemo.sh#!/bin/shnameAliceechoHello,$namels/nonexistent2/dev/null $sh-xdemo.sh nameAlice echoHello, AliceHello, Alice ls/nonexistent# 不存在的文件无输出# 关键 行的就是**实际执行**的命令# 常用于定位脚本卡在哪里# 2. -v 详细模式 $sh-vdemo.sh#!/bin/shnameAlicenameAliceechoHello,$nameechoHello, AliceHello, Alicels/nonexistent2/dev/null ls/nonexistent# 先打印**源代码**行无 再执行带 # 3. -n 仅语法检查不执行 $catsyntax_error.sh#!/bin/shif[$x1]# 缺 thenechox is 1fi$sh-nsyntax_error.sh syntax_error.sh: line3: syntax error: unexpected end offile# 退出码 2$echo$?2# 完整命令带错误$catsyntax_ok.sh#!/bin/shforiin123;doecho$idone$sh-nsyntax_ok.sh $echo$?0# 无输出 语法正确# 4. 组合使用 -n -v -x $sh-nvxscript.sh# 三重输出源码 → 语法检查 → 执行跟踪# 生产环境一般只用 -n 或 -x示例 3sh vs bash 关键差异# 差异 1[[ ]] vs [ ] # bash 支持 [[ ]]$bash-c[[ abc *b* ]] echo matchmatch# sh 不支持 [[ ]]必须用 [ ] 模式匹配$ dash-c[[ abc *b* ]] echo matchdash:1:[[: not found# dash 报错$ dash-ccase abc in *b*) echo match;; esacmatch# dash 用 case 或 [ $x $y ]**单个等号**# 差异 2数组 # bash 支持数组$bash-carr(a b c); echo ${arr[1]}b# dash 不支持数组$ dash-carr(a b c); echo ${arr[1]}dash:2: Bad substitution# 用 set 替代$ dash-cset -- a b c; echo $2b# 差异 3函数定义 # bash 两种写法都行$bash-cfunction foo() { echo hi; } ; foohi# dash 仅 function 关键字或 () 均可$ dash-cfoo() { echo hi; } ; foohi# 差异 4here-string # bash 支持$bash-ccat hellohello# dash 不支持$ dash-ccat hello# 无输出here-string 被忽略# 改用 echo pipe$ dash-cecho hello | cathello# 差异 5$RANDOM、$SECONDS # bash 特有$bash-cecho $RANDOM20315$ dash-cecho $RANDOM$RANDOM# dash 输出字面量# 差异 6花括号扩展 # bash 支持$bash-cecho {1..5}12345$ dash-cecho {1..5}{1..5}# 字面输出# 改用 seq$ dash-cseq 1 512345示例 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}echoHello,$name# 数组用 set 模拟set-- apple banana cherryecho第二个水果:$2# for 循环forfin/etc/*.conf;doecho配置文件:$fdone# if 用单个 POSIX 严格if[$nameroot];thenecho管理员elseecho普通用户fi# Bash-only 脚本 $cat/opt/scripts/bash_only.sh#!/bin/bash# 用 [[ ]] 比较if[[$nameroot]];thenecho管理员fi# 数组arr(a b c)echo${arr[1]}# here-stringgreppattern$text# 关联数组declare-Auser_age user_age[alice]30echo${user_age[alice]}# 字符串切片strhello worldecho${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 时$sshalicehost $echo$0-dash# dash 启动- 是登录标记示例 6sh 在系统脚本中的角色# 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-cexec /opt/myapp/bin/server# 用 sh -c 包装复杂命令# 5. 用户 crontab 任务可显式指定 $crontab-e*/5 * * * * /bin/sh /opt/scripts/backup.sh# 显式指定 sh 避免环境差异示例 7sh -c 的安全与转义# 1. 嵌套 sh -c $sh-csh -c echo nestednested# 2. 引号转义 $sh-cecho Double quotesDouble quotes# 内部双引号会被 sh -c 的命令字符串识别# 复杂场景$sh-cecho $(date)2024年1月15日 星期一14:30:00 CST# 外部是双引号 → $() 会被**当前 shell** 解释# 想要 sh -c 内解释 $()$sh-cecho $(date)2024年1月15日 星期一14:30:00 CST# 内部单引号 → 内部 sh 解释 $()# 3. 性能对比 # 启动速度单位ms$timedash-ctruereal 0m0.002s# 2ms$timebash-ctruereal 0m0.015s# 15ms# 对 1000 个 sh -c 调用# dash2 秒# bash15 秒# 这是 Debian 改用 dash 的核心理由# 4. 函数内调用 sh -c my_func(){localresult$(sh-cecho$1)echoResult:$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. 变量赋值无空格nameAlice# 或nameAlice# 没有空格就能省略引号# 3. 命令替换POSIX 用 不是 $()date1date%Fdate2$(date%F)# $() 是 POSIX 标准更推荐# 4. 条件判断[ 单等号POSIX 严格if[$nameAlice];thenechoMatchfi# 5. for 循环不依赖 bash 扩展forfin*.txt;do[-e$f]||continue# 处理空目录echoFile:$fdone# 6. while 循环n0while[$n-lt5];doechon $nn$((n1))# POSIX 算术done# 7. 退出码exit_code$?if[$exit_code-ne0];thenechoFailed with code:$exit_codeexit$exit_codefi# 8. 函数my_log(){level$1shiftecho[$(date%F %T)] [$level]$*2}my_logINFOApplication started# 9. 错误处理trapcleanup(){echoCleaning up...rm-f/tmp/myapp.lock}trapcleanup EXIT INTTERM# 10. 读文件whileIFSread-rline;doechoLine:$linedone/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 系指向dashCentOS/RHEL 系指向bash。脚本可移植必须用 POSIX 语法。2.sh -x调试会暴露变量$secretmypassword$sh-xscript.sh secretmypassword# ⚠️ 密码会显示调试敏感脚本前先脱敏。3.sh与bash启动文件不同sh:/etc/profile、~/.profilebash:/etc/profile、~/.bash_profile、~/.bashrc在 sh 登录时~/.bashrc 不会被读。4. -e 选项的边界set-efalse# 立即退出echonever prints但if false; then不触发条件命令不算错。与set -o pipefail配合防止管道错失。5. dash 的 “echo -e” 不支持$ dash-cecho -e a\nb-ea b# 把 -e 当字面量dash 的echo是内建BSD 风格。改用printf$ dash-cprintf a\nb\na b6.set -u与$冲突set-uecho$# 没参数会报错正确写法echo${:-}# 没参数时用空字符串7. sh -c ‘多行’ 的换行处理$sh-cecho a; echo ba b $sh-cecho a echo baechob# 字面输出因为外层双引号未执行 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 系指dashRHEL 系指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扩展最多的 shdashDebian Almquist ShellPOSIX 严格ashAlmquist ShellBusybox 嵌入式kshKorn Shell商业传统zshZ ShellmacOS 默认fishFriendly Shell用户友好csh/tcshC ShellBSDbusybox sh嵌入式 Linux 最小 shellshellcheckShell 脚本静态分析强烈推荐setshell 内置设置/取消选项env执行命令并可设置环境变量exec替换当前进程source/.当前 shell 读取并执行不同 sh 行为可能差异