Shell流程控制if/case/for/while让脚本活起来上一篇我们学会了Shell脚本的基础——变量、输出、重定向。但到目前为止我们的脚本都是一根筋从上到下顺序执行没有任何判断和循环。这就好比写代码只有赋值语句没有if和for根本没法处理复杂的业务逻辑。今天我们就来给脚本加上大脑和双腿。一、条件判断让脚本学会思考1.1 test与[]条件表达式的基础在Shell中条件判断的核心是test命令或者它的简写[]# 两种写法完全等价test1-eq1[1-eq1]# 判断上一条命令是否成功[1-eq1]echo相等||echo不相等# 输出相等注意[后面和]前面必须有空格这是新手最常犯的错误。1.2 if语句三种形态单分支#!/bin/bash# 判断文件是否存在file/etc/passwdif[-f$file];thenecho文件存在fi双分支#!/bin/bash# 判断服务是否在运行ifpgrep-xnginx/dev/null;thenechoNginx正在运行elseechoNginx未运行fi多分支#!/bin/bash# 根据成绩判断等级score85if[$score-ge90];thenecho优秀elif[$score-ge80];thenecho良好elif[$score-ge60];thenecho及格elseecho不及格fi1.3 常用的判断条件文件判断[-ffile]# 是否为普通文件[-ddir]# 是否为目录[-epath]# 是否存在[-rfile]# 是否可读[-wfile]# 是否可写[-xfile]# 是否可执行[-sfile]# 文件存在且不为空字符串判断[-z$str]# 字符串是否为空[-n$str]# 字符串是否非空[$a$b]# 字符串是否相等[$a!$b]# 字符串是否不等数字判断[$a-eq$b]# 等于 (equal)[$a-ne$b]# 不等于 (not equal)[$a-gt$b]# 大于 (greater than)[$a-ge$b]# 大于等于 (greater or equal)[$a-lt$b]# 小于 (less than)[$a-le$b]# 小于等于 (less or equal)逻辑组合# 与两个条件都成立[$a-gt0][$a-lt100]# || 或至少一个条件成立[$userroot]||[$useradmin]# ! 非取反[!-f/tmp/lock]1.4 [[]]增强版条件判断[[]]是[]的增强版支持正则匹配和通配符# 通配符匹配filenameapp.logif[[$filename*.log]];thenecho这是一个日志文件fi# 正则匹配emailuserexample.comif[[$email~^[a-zA-Z0-9._%-][a-zA-Z0-9.-]\.[a-zA-Z]{2,}$]];thenecho邮箱格式正确fi# 数字运算不需要-eq等直接用比较符num42if((num40));thenecho大于40fi1.5 实战服务管理脚本#!/bin/bash# 功能服务状态检查与管理service_name$1# 参数检查if[-z$service_name];thenecho用法:$0服务名exit1fi# 检查服务状态ifsystemctl is-active--quiet$service_name;thenecho$service_name正在运行echo进程信息:psaux|grep$service_name|grep-vgrepelseecho$service_name未运行read-p是否启动该服务? (y/n): choiceif[$choicey];thensystemctl start$service_nameif[$?-eq0];thenecho服务启动成功elseecho服务启动失败fififi二、case语句多分支的优雅写法当分支条件比较多时if/elif会显得很臃肿。这时候case语句就派上用场了。2.1 基本语法#!/bin/bash# 简单的菜单脚本echo请选择操作echo1) 查看磁盘echo2) 查看内存echo3) 查看CPUread-p请输入选项: choicecase$choicein1)df-h;;2)free-m;;3)top-bn1|head-5;;*)echo无效选项;;esac2.2 模式匹配case支持通配符模式比if更灵活#!/bin/bash# 根据文件扩展名判断类型filename$1case$filenamein*.jpg|*.png|*.gif)echo图片文件;;*.mp4|*.avi|*.mkv)echo视频文件;;*.tar.gz|*.zip|*.rar)echo压缩文件;;*.sh)echoShell脚本;;*)echo未知文件类型;;esac2.3 实战Kubernetes部署管理脚本这是一个比较完整的例子展示了case在实际项目中的应用#!/bin/bash# 功能Kubernetes环境部署管理PS3请选择部署阶段: env_array(基础环境 高可用 K8s基础 主节点 从节点 退出)selectstagein${env_array[]};docase$stagein基础环境)echo 基础环境部署 echo1. 配置主机名和hostsecho2. 关闭防火墙和SELinuxecho3. 配置时间同步echo4. 加载内核模块;;高可用)echo 高可用环境部署 echo1. 部署Keepalivedecho2. 部署HAProxy;;K8s基础)echo K8s基础环境部署 echo1. 部署etcd集群echo2. 生成集群证书;;主节点)echo 主节点部署 echo1. 部署apiserverecho2. 部署controller-managerecho3. 部署scheduler;;从节点)echo 从节点部署 echo1. 部署kubeletecho2. 部署kube-proxyecho3. 部署容器运行时;;退出)echo退出部署平台break;;*)echo无效选项请重新选择;;esacdone三、for循环遍历的艺术3.1 基本语法# 方式1遍历列表foriin12345;doecho数字:$idone# 方式2使用范围foriin{1..5};doecho数字:$idone# 方式3C语言风格for((i1;i5;i));doecho数字:$idone# 方式4遍历命令输出forfilein$(ls/tmp/*.log);doecho日志文件:$filedone# 方式5遍历脚本参数forargin$;doecho参数:$argdone3.2 实战案例批量创建用户#!/bin/bash# 批量创建用户并设置随机密码foriin{1..5};dousernameuser$ipassword$(openssl rand-base648)useradd$usernameecho$password|passwd--stdin$username/dev/null21echo用户:$username, 密码:$passworddone网段主机存活检测#!/bin/bash# 扫描10.0.0.0/24网段的存活主机network10.0.0live_count0foriin{1..254};doip$network.$i# -c1发1个包-W1超时1秒ifping-c1-W1$ip/dev/null21;thenecho$ip存活((live_count))fidoneecho扫描完成存活主机:$live_count台计算1到100的和#!/bin/bashsum0for((i1;i100;i));do((sumi))doneecho12...100 $sum3.3 嵌套循环九九乘法表#!/bin/bash# 打印九九乘法表for((i1;i9;i));dofor((j1;ji;j));doprintf%d×%d%-4d$j$i$((i*j))doneechodone输出效果1×11 1×22 2×24 1×33 2×36 3×39 ...四、while循环条件驱动的循环4.1 基本语法# 基本while循环count1while[$count-le5];doecho第$count次((count))done# 无限循环常用于守护进程whiletrue;doecho运行中...sleep5done4.2 while read逐行处理文件这是while最实用的用法没有之一#!/bin/bash# 逐行读取文件whilereadline;doecho读取到:$linedone/etc/hosts#!/bin/bash# 从文件读取IP列表并测试连通性whilereadip;doifping-c1-W1$ip/dev/null21;thenecho$ip正常elseecho$ip不可达fidoneip_list.txt实战持续监控网站状态#!/bin/bash# 持续检测网站存活状态site_urlwww.baidu.comcheck_interval10# 检查间隔秒echo开始监控$site_url...whiletrue;dostatus$(curl-s-o/dev/null-w%{http_code}$site_url)if[$status200];thenecho$(date%F %T)-$site_url正常 (HTTP$status)elseecho$(date%F %T)-$site_url异常 (HTTP$status)# 这里可以发告警fisleep$check_intervaldone4.3 until循环反向whileuntil和while逻辑相反——条件不满足时执行循环#!/bin/bash# until循环示例count1until[$count-gt5];doecho第$count次((count))done五、循环控制break、continue、exit5.1 break跳出循环#!/bin/bash# 找到第一个大于50的数foriin{1..100};doif[$i-gt50];thenecho找到:$ibreak# 跳出整个循环fidone在嵌套循环中break默认跳出内层循环。如果要跳出外层循环需要指定层级#!/bin/bash# break 2 跳出外层循环foriin{1..5};doforjin{a..d};doif[$jc];thenbreak2# 跳出两层循环fiecho$i$jdonedone# 输出1 a, 1 b遇到c时直接跳出两层5.2 continue跳过本次循环#!/bin/bash# 打印1-10中的奇数foriin{1..10};doif[$((i%2))-eq0];thencontinue# 跳过偶数fiecho$idone5.3 exit退出脚本#!/bin/bash# 带错误码退出if[$#-ne1];thenecho用法:$0参数exit1# 非0表示异常退出fiecho正常执行exit0# 0表示正常退出5.4 shift参数左移shift用于遍历脚本参数在处理不定数量参数时很有用#!/bin/bash# 逐个处理所有参数while[-n$1];doecho处理参数:$1shift# 移除第一个参数后面的参数前移done执行效果/bin/bash shift_demo.sh a b c# 处理参数: a# 处理参数: b# 处理参数: c六、select交互式菜单select可以快速生成一个带编号的菜单#!/bin/bash# 简单的软件选择菜单PS3请选择要安装的软件: softwares(NginxMySQLRedis退出)selectsoftwarein${softwares[]};docase$softwareinNginx)echo安装Nginx...yuminstall-ynginxbreak;;MySQL)echo安装MySQL...yuminstall-ymysql-serverbreak;;Redis)echo安装Redis...yuminstall-yredisbreak;;退出)break;;*)echo无效选项;;esacdoneselect的特点是自动生成菜单、自动接收用户输入配合case使用非常方便。
Shell流程控制:if/case/for/while让脚本活起来
发布时间:2026/6/12 23:44:18
Shell流程控制if/case/for/while让脚本活起来上一篇我们学会了Shell脚本的基础——变量、输出、重定向。但到目前为止我们的脚本都是一根筋从上到下顺序执行没有任何判断和循环。这就好比写代码只有赋值语句没有if和for根本没法处理复杂的业务逻辑。今天我们就来给脚本加上大脑和双腿。一、条件判断让脚本学会思考1.1 test与[]条件表达式的基础在Shell中条件判断的核心是test命令或者它的简写[]# 两种写法完全等价test1-eq1[1-eq1]# 判断上一条命令是否成功[1-eq1]echo相等||echo不相等# 输出相等注意[后面和]前面必须有空格这是新手最常犯的错误。1.2 if语句三种形态单分支#!/bin/bash# 判断文件是否存在file/etc/passwdif[-f$file];thenecho文件存在fi双分支#!/bin/bash# 判断服务是否在运行ifpgrep-xnginx/dev/null;thenechoNginx正在运行elseechoNginx未运行fi多分支#!/bin/bash# 根据成绩判断等级score85if[$score-ge90];thenecho优秀elif[$score-ge80];thenecho良好elif[$score-ge60];thenecho及格elseecho不及格fi1.3 常用的判断条件文件判断[-ffile]# 是否为普通文件[-ddir]# 是否为目录[-epath]# 是否存在[-rfile]# 是否可读[-wfile]# 是否可写[-xfile]# 是否可执行[-sfile]# 文件存在且不为空字符串判断[-z$str]# 字符串是否为空[-n$str]# 字符串是否非空[$a$b]# 字符串是否相等[$a!$b]# 字符串是否不等数字判断[$a-eq$b]# 等于 (equal)[$a-ne$b]# 不等于 (not equal)[$a-gt$b]# 大于 (greater than)[$a-ge$b]# 大于等于 (greater or equal)[$a-lt$b]# 小于 (less than)[$a-le$b]# 小于等于 (less or equal)逻辑组合# 与两个条件都成立[$a-gt0][$a-lt100]# || 或至少一个条件成立[$userroot]||[$useradmin]# ! 非取反[!-f/tmp/lock]1.4 [[]]增强版条件判断[[]]是[]的增强版支持正则匹配和通配符# 通配符匹配filenameapp.logif[[$filename*.log]];thenecho这是一个日志文件fi# 正则匹配emailuserexample.comif[[$email~^[a-zA-Z0-9._%-][a-zA-Z0-9.-]\.[a-zA-Z]{2,}$]];thenecho邮箱格式正确fi# 数字运算不需要-eq等直接用比较符num42if((num40));thenecho大于40fi1.5 实战服务管理脚本#!/bin/bash# 功能服务状态检查与管理service_name$1# 参数检查if[-z$service_name];thenecho用法:$0服务名exit1fi# 检查服务状态ifsystemctl is-active--quiet$service_name;thenecho$service_name正在运行echo进程信息:psaux|grep$service_name|grep-vgrepelseecho$service_name未运行read-p是否启动该服务? (y/n): choiceif[$choicey];thensystemctl start$service_nameif[$?-eq0];thenecho服务启动成功elseecho服务启动失败fififi二、case语句多分支的优雅写法当分支条件比较多时if/elif会显得很臃肿。这时候case语句就派上用场了。2.1 基本语法#!/bin/bash# 简单的菜单脚本echo请选择操作echo1) 查看磁盘echo2) 查看内存echo3) 查看CPUread-p请输入选项: choicecase$choicein1)df-h;;2)free-m;;3)top-bn1|head-5;;*)echo无效选项;;esac2.2 模式匹配case支持通配符模式比if更灵活#!/bin/bash# 根据文件扩展名判断类型filename$1case$filenamein*.jpg|*.png|*.gif)echo图片文件;;*.mp4|*.avi|*.mkv)echo视频文件;;*.tar.gz|*.zip|*.rar)echo压缩文件;;*.sh)echoShell脚本;;*)echo未知文件类型;;esac2.3 实战Kubernetes部署管理脚本这是一个比较完整的例子展示了case在实际项目中的应用#!/bin/bash# 功能Kubernetes环境部署管理PS3请选择部署阶段: env_array(基础环境 高可用 K8s基础 主节点 从节点 退出)selectstagein${env_array[]};docase$stagein基础环境)echo 基础环境部署 echo1. 配置主机名和hostsecho2. 关闭防火墙和SELinuxecho3. 配置时间同步echo4. 加载内核模块;;高可用)echo 高可用环境部署 echo1. 部署Keepalivedecho2. 部署HAProxy;;K8s基础)echo K8s基础环境部署 echo1. 部署etcd集群echo2. 生成集群证书;;主节点)echo 主节点部署 echo1. 部署apiserverecho2. 部署controller-managerecho3. 部署scheduler;;从节点)echo 从节点部署 echo1. 部署kubeletecho2. 部署kube-proxyecho3. 部署容器运行时;;退出)echo退出部署平台break;;*)echo无效选项请重新选择;;esacdone三、for循环遍历的艺术3.1 基本语法# 方式1遍历列表foriin12345;doecho数字:$idone# 方式2使用范围foriin{1..5};doecho数字:$idone# 方式3C语言风格for((i1;i5;i));doecho数字:$idone# 方式4遍历命令输出forfilein$(ls/tmp/*.log);doecho日志文件:$filedone# 方式5遍历脚本参数forargin$;doecho参数:$argdone3.2 实战案例批量创建用户#!/bin/bash# 批量创建用户并设置随机密码foriin{1..5};dousernameuser$ipassword$(openssl rand-base648)useradd$usernameecho$password|passwd--stdin$username/dev/null21echo用户:$username, 密码:$passworddone网段主机存活检测#!/bin/bash# 扫描10.0.0.0/24网段的存活主机network10.0.0live_count0foriin{1..254};doip$network.$i# -c1发1个包-W1超时1秒ifping-c1-W1$ip/dev/null21;thenecho$ip存活((live_count))fidoneecho扫描完成存活主机:$live_count台计算1到100的和#!/bin/bashsum0for((i1;i100;i));do((sumi))doneecho12...100 $sum3.3 嵌套循环九九乘法表#!/bin/bash# 打印九九乘法表for((i1;i9;i));dofor((j1;ji;j));doprintf%d×%d%-4d$j$i$((i*j))doneechodone输出效果1×11 1×22 2×24 1×33 2×36 3×39 ...四、while循环条件驱动的循环4.1 基本语法# 基本while循环count1while[$count-le5];doecho第$count次((count))done# 无限循环常用于守护进程whiletrue;doecho运行中...sleep5done4.2 while read逐行处理文件这是while最实用的用法没有之一#!/bin/bash# 逐行读取文件whilereadline;doecho读取到:$linedone/etc/hosts#!/bin/bash# 从文件读取IP列表并测试连通性whilereadip;doifping-c1-W1$ip/dev/null21;thenecho$ip正常elseecho$ip不可达fidoneip_list.txt实战持续监控网站状态#!/bin/bash# 持续检测网站存活状态site_urlwww.baidu.comcheck_interval10# 检查间隔秒echo开始监控$site_url...whiletrue;dostatus$(curl-s-o/dev/null-w%{http_code}$site_url)if[$status200];thenecho$(date%F %T)-$site_url正常 (HTTP$status)elseecho$(date%F %T)-$site_url异常 (HTTP$status)# 这里可以发告警fisleep$check_intervaldone4.3 until循环反向whileuntil和while逻辑相反——条件不满足时执行循环#!/bin/bash# until循环示例count1until[$count-gt5];doecho第$count次((count))done五、循环控制break、continue、exit5.1 break跳出循环#!/bin/bash# 找到第一个大于50的数foriin{1..100};doif[$i-gt50];thenecho找到:$ibreak# 跳出整个循环fidone在嵌套循环中break默认跳出内层循环。如果要跳出外层循环需要指定层级#!/bin/bash# break 2 跳出外层循环foriin{1..5};doforjin{a..d};doif[$jc];thenbreak2# 跳出两层循环fiecho$i$jdonedone# 输出1 a, 1 b遇到c时直接跳出两层5.2 continue跳过本次循环#!/bin/bash# 打印1-10中的奇数foriin{1..10};doif[$((i%2))-eq0];thencontinue# 跳过偶数fiecho$idone5.3 exit退出脚本#!/bin/bash# 带错误码退出if[$#-ne1];thenecho用法:$0参数exit1# 非0表示异常退出fiecho正常执行exit0# 0表示正常退出5.4 shift参数左移shift用于遍历脚本参数在处理不定数量参数时很有用#!/bin/bash# 逐个处理所有参数while[-n$1];doecho处理参数:$1shift# 移除第一个参数后面的参数前移done执行效果/bin/bash shift_demo.sh a b c# 处理参数: a# 处理参数: b# 处理参数: c六、select交互式菜单select可以快速生成一个带编号的菜单#!/bin/bash# 简单的软件选择菜单PS3请选择要安装的软件: softwares(NginxMySQLRedis退出)selectsoftwarein${softwares[]};docase$softwareinNginx)echo安装Nginx...yuminstall-ynginxbreak;;MySQL)echo安装MySQL...yuminstall-ymysql-serverbreak;;Redis)echo安装Redis...yuminstall-yredisbreak;;退出)break;;*)echo无效选项;;esacdoneselect的特点是自动生成菜单、自动接收用户输入配合case使用非常方便。