Shell 编程

张开发
2026/4/14 12:30:51 15 分钟阅读

分享文章

Shell 编程
一、Shell 介绍定义Shell 是 Unix/Linux 系统中用户与内核之间的接口程序属于命令解释器。与操作系统的关系Shell 充当用户与操作系统之间的桥梁负责解析用户输入的命令并转化为操作系统可理解的指令。它不仅提供了与操作系统交互的界面还支持用户通过脚本自动化执行复杂任务拓展了操作系统的功能与灵活性。作用解释用户输入的命令并提交给操作系统执行同时提供编程环境。编程语言分类视角编程语言分为编译型和解释型。编译型语言如 C/C需借助编译器如 gcc/g解释型语言如 Shell 脚本、Python 等。Ubuntu 系统中使用的解释器是bash此外还有 ksh、csh 等。常见 Shell 类型对比Shell 名称描述特点典型使用场景Ubuntu 中的情况BashLinux 系统中最常用的默认交互式 shell兼容传统 shell 脚本支持命令补全、历史记录、自定义别名日常命令行操作、脚本编写默认用户登录 shellsh符合 POSIX 标准的基础 shell语法简单功能精简不支持交互式增强功能系统服务启动脚本、兼容性脚本实际指向 dashZsh功能强大的现代化 shell智能命令补全、主题美化、支持插件化定制开发者、追求高效交互的用户需手动安装Fish以交互友好性为核心的 shell自动命令建议、语法高亮、配置简单新手用户、注重交互体验的场景需手动安装Dash轻量高效的 shell启动快资源占用极低仅支持基础脚本功能系统初始化脚本、低资源环境/bin/sh 的默认实现二、第一个 Shell 脚本Shell 脚本是一种文本文件其中有序集合了一系列操作系统命令广泛应用于系统管理、自动化运维、批处理任务等场景。Shell 基本结构文件扩展名通常习惯用.sh作为扩展名不是强制要求。shebang 行一般写成#!/bin/bash这行的作用是指定执行脚本的 shell 解释器路径。注释规范单行注释以#开头。多行注释在 Bash 中可用EOF和EOF包裹起来。脚本执行方式bash复制# 1. 赋予执行权限后直接运行 chmod x xxx.sh ./xxx.sh # 2. shell 解释器运行 bash xxx.sh sh xxx.sh # 3. 使用 source 执行在当前 shell 环境中执行 source xxx.sh . xxx.sh执行方式对比执行方式优点缺点适用场景赋予执行权限后直接运行执行效率高无需额外启动解释器进程需手动赋予权限步骤稍繁琐正式环境中已稳定的脚本部署shell 解释器运行无需提前设置权限可灵活选用不同解释器每次执行需明确指定解释器效率略低脚本开发阶段的临时测试使用 source 执行在当前 shell 环境内执行变量、函数可直接作用于当前环境不能独立运行脚本出错可能干扰当前 shell 环境加载或更新 shell 配置文件如 .bashrc三、Shell 中的变量变量是存储数据的容器用于存储字符串、数字等类型的数据。变量的定义命名规则变量名由字母、数字和下划线组成不能以数字开头。赋值格式三种可通用bash复制变量名初始值 变量名初始值 变量名初始值变量调用使用$变量名或${变量名}推荐使用${变量名}形式可避免歧义。bash复制str2${str1}world # 正确 str4$str1world # 错误⚠️注意事项Shell 中定义的变量没有数据类型变量的值都视为字符串定义变量时等号两边不允许有空格当变量的初始值包含空格时需用单引号或双引号括起来。变量的类型变量类型定义作用域声明方式命名规范典型场景系统变量由系统预定义存储环境信息所有 shell 进程和脚本系统自动设置无需声明全大写$HOME、$USER、$PATH用户变量用户自定义当前 shell 进程或脚本变量名值小写或驼峰式临时存储计算结果传递数据给函数环境变量用户自定义可在当前 shell 及子进程中访问当前 Shell 及其所有子进程export 变量名值全大写多脚本共享配置系统级参数局部变量作用域受限的变量隐式当前 shell显式仅在函数内部显式local 变量名值小写或驼峰式避免变量污染全局作用域特殊变量与位置参数变量含义$0当前脚本的名称$?上一条命令的退出状态码0 表示成功非 0 表示失败$1-$9依次对应执行脚本时传递的第 1-9 个参数${10}第 10 个及以上的参数$*所有参数整体处理$所有参数逐个处理$#参数个数不含脚本文件名修饰变量的关键字readonly使变量成为只读属性赋值后不可修改不能被unset删除。bash复制readonly 变量名值unset取消变量的定义删除后变量引用返回空值不能用于 readonly 变量。bash复制unset 变量名local在函数内部使用创建局部变量仅在函数内有效避免污染全局作用域。bash复制function 函数名() { local 变量名值; }四、Shell 中的算术运算Shell 变量默认是字符串进行算术运算需借助算术运算符方式语法格式特点示例expr命令expr 操作数1 运算符 操作数2较古老操作数与运算符间需空格*需转义expr 5 \* 3**双括号((...))**((变量 表达式))Bash 推荐语法简洁支持 C 风格运算符如、((a 5 3))$((...))$((表达式))用于直接替换算术表达式结果无需空格echo $((5 3))五、Shell 中的数组Shell 仅支持一维数组无需预先定义大小索引默认从0开始。数组的定义bash复制# 直接赋值法 数组名(元素1 元素2 元素3 ...) # 逐个赋值法 数组名[索引]元素数组元素的访问bash复制${数组名[索引]} # 访问单个元素 ${数组名[]} # 访问所有元素每个元素作为独立参数适合循环遍历 ${数组名[*]} # 访问所有元素所有元素作为整体字符串 ${#数组名[]} # 获取数组长度数组的操作bash复制数组名(新元素) # 末尾添加元素 数组名[新索引]新元素 # 指定索引添加 数组名[索引]新值 # 修改元素 unset 数组名[索引] # 删除元素数组变稀疏索引不重排 ${数组名[]:起始索引:长度} # 截取数组六、read 和 echo 命令read 命令作用Shell 内置命令用于从标准输入键盘或文件中读取数据并赋值给变量。语法read 选项 变量名1 变量名2 ...选项功能描述示例-p显示提示信息read -p 输入姓名 name-s静默模式输入内容不显示适用于密码等敏感信息read -s -p 密码 pass-n N读取 N 个字符后自动结束无需按回车read -n 2 input-t N设置超时时间秒超时后退出并返回非零状态码read -t 3 input-a将输入按空格分割为数组read -a arr-r禁止反斜杠转义将反斜杠视为普通字符read -r home-d指定行结束符默认为回车read -d : input⚠️注意事项引用变量时用双引号包裹防止空值或特殊字符问题用户直接回车会使变量为空可用参数扩展设默认值${变量名:-默认值}echo 命令作用Shell 脚本中最常用的输出工具用于向终端打印文本或变量值配合重定向符号、将内容写入文件。语法echo 选项 字符串/变量选项作用示例-e启用转义字符解析如\n、\techo -e 第一行\n第二行-n不换行输出echo -n Loading...-E禁用转义字符解析默认行为echo -E a\nb转义字符含义\n换行\t制表符Tab 缩进\\反斜杠\\033[31m红色文本搭配\033[0m重置七、Shell 中的条件判断if 语句bash复制说明((表达式))是 Bash 特有的算术表达式支持、-、*、/、、等运算符。test 命令与[ ]基本格式test 表达式或[ 表达式 ]本质调用 test 命令返回状态码0 表示条件成立非 0 表示条件不成立。⚠️注意使用方括号[ ]时方括号和表达式之间必须有空格建议将变量用双引号引起来。数值判断操作符含义等价数学符号-eq等于-ne不等于!-gt大于-lt小于-ge大于等于-le小于等于字符串判断操作符作用-z STRING如果 STRING 长度为 0空字符串则条件为真-n STRING如果 STRING 长度大于 0非空字符串则条件为真STRING1 STRING2两个字符串相等则为真和等价STRING1 ! STRING2两个字符串不相等则为真STRING1 STRING2STRING1 字典序大于 STRING2需要转义STRING1 STRING2STRING1 字典序小于 STRING2需要转义逻辑判断操作符含义示例-a逻辑与AND同时都满足[ $a -gt 5 -a $b -lt 30 ]-o逻辑或OR满足其一即可[ $a -eq 0 -o $b -eq 20 ]!逻辑非NOT取反[ ! -d $dir ]文件判断操作符作用描述-e FILE检查文件/目录是否存在-f FILE检查是否为普通文件-d FILE检查是否为目录-r FILE检查当前用户是否有可读权限-w FILE检查当前用户是否有可写权限-x FILE检查当前用户是否有可执行权限-s FILE检查文件是否存在且非空文件大小 0-L FILE检查是否为符号链接FILE1 -nt FILE2检查 FILE1 是否比 FILE2 新FILE1 -ot FILE2检查 FILE1 是否比 FILE2 旧[[ ]]的使用[[ ... ]]是 Bash 提供的高级条件测试语法比传统的[ ... ]更强大、更灵活。主要优势无需转义特殊字符、、!等可直接使用支持短路求值左侧为假则右侧不执行||左侧为真则右侧不执行语法更友好直接使用/||不需要记忆-a/-o安全处理未定义变量未定义变量视为空字符串避免语法错误。bash复制if [[ 条件表达式1 ]]; then shell语句1 elif [[ 条件表达式2 ]]; then shell语句2 else shell语句3 fi三种条件判断对比语法形式数值比较字符串比较文件测试适用场景(( ... ))(( a b ))不适用不适用专注纯算术运算test[ ... ][ $a -eq $b ][ $str1 $str2 ][ -f $file ]对兼容性要求极高的脚本[[ ... ]][[ $a -eq $b ]][[ $str1 $str2 ]][[ -f $file ]]Bash 脚本开发推荐使用case...in 语句用于多路分支结构类似其他语言的switch-case语句。bash复制case 变量 in 模式1) 命令序列1 ;; 模式2) 命令序列2 ;; *) 默认命令序列 ;; esac说明;;结束当前模式的命令序列类似于其他语言中的break*默认模式当变量与所有模式都不匹配时执行esaccase...in语句的结束标志case 反写支持通配符匹配*匹配任意字符序列?匹配单个字符。select...in 语句用于创建交互式菜单自动为每个选项生成编号从 1 开始。bash复制select 变量名 in 选项1 选项2 选项3... do 命令序列 [break] # 可选用于退出循环 done优势自动生成编号菜单无需手动编写编号逻辑对无效输入自动循环提示Shell 内置命令无需第三方工具。八、Shell 中的循环结构for 循环适用于已知要遍历的元素集合或明确循环次数的场景。bash复制# 遍历列表 for 变量 in 列表或数组元素; do 命令1 命令2 done # 数字范围循环C 风格 for ((初始值; 条件; 增量或减量)); do 命令1 命令2 donewhile 循环只要条件为真就持续循环适用于条件动态变化或不确定循环次数的情况。bash复制while 条件判断; do 命令1 命令2 done应用场景等待特定条件满足、动态读取输入、持续监控资源状态等。until 循环与while循环相反条件为假时持续循环条件变为真时结束。bash复制until 条件判断; do 命令1 命令2 done优势在需要等待某条件从假变为真的场景中逻辑表达更自然清晰。 例如不必写while [ ! -f file.txt ]而是直接用until [ -f file.txt ]。应用场景等待特定条件满足如等待文件出现、进程启动完成重试操作直到成功如网络连接、命令执行成功break 和 continue关键字功能使用场景break强制终止当前循环跳出循环执行后续代码找到目标值后停止搜索、用户输入退出指令时continue跳过当前轮循环剩余代码直接开始下一轮循环过滤不需要处理的情况、忽略错误输入九、Shell 中的函数函数定义与调用bash复制# 标准格式 function 函数名() { 命令1 命令2 [return 返回值] # 可选返回值范围 0-255 } # 简化格式省略 function 关键字 函数名() { 命令1 命令2 } # 函数调用直接使用函数名参数跟在函数名后面空格分隔 函数名 参数1 参数2函数参数变量含义$1,$2, ...,$n第 1 到第 n 个参数$0脚本本身的名称$#参数的个数$所有参数将参数视为独立个体$*所有参数将所有参数视为一个整体函数返回值方式一通过return语句返回状态码设置函数的退出状态码范围0-255$?变量获取return语句会立即终止函数执行仅作用于函数类似exit但范围限于函数仅能返回整数。方式二通过echo输出返回结果将计算结果通过标准输出返回调用者通过命令替换$(...)捕获可返回任意文本内容不限于数字需避免在函数中输出调试信息以免干扰返回值。bash复制# 示例通过 echo 返回结果 get_result() { echo 计算结果 } result$(get_result) echo $result函数输出捕获方式限制用途return$?仅能返回整数0-255主要用于表示执行状态返回状态码成功/失败echo$(...)支持任意类型数据字符串、数字、多行内容返回实际计算结果现代 Shell 推荐用法总结Shell 编程的核心在于熟练掌握变量、条件判断、循环结构和函数四大模块。推荐在 Bash 环境下使用[[ ]]进行条件测试、使用$((...))进行算术运算代码更简洁安全。

更多文章