循环与case多分支

5322 字
27 分钟
循环与case多分支

循环 && case多分支#

[TOC]


初识while#

while 属于循环语句,条件为真时反复执行循环体

Terminal window
while 条件
do
命令集
done
# 条件满足就一直循环,直到条件不满足或遇到break/exit才退出
Important

==while true== 表示死循环,必须配合 breakexit 来退出,否则永远不会停止


break跳出循环#

Tip

break 用于跳出当前层循环,break N 跳 N 层

✅️ break N中的N表示跳出的循环层数,默认 break = break 1

1)break跳出一层
[root@shell ~]#cat while.sh
#!/bin/bash
while true
do
echo 1...
while true
do
echo 2...
sleep 1
break # 跳出内层while
done
done
# break默认只跳一层,外层while继续执行
'外层循环会不断进入内层→内层break→外层再进入内层...'
# 效果: 1...2...1...2...1...2... 无限循环
2)break 2 跳出两层
[root@shell ~]#cat while.sh
#!/bin/bash
while true
do
echo 1...
while true
do
echo 2...
sleep 1
break 2 # 跳出2层循环
done
done
echo done............
[root@shell ~]#sh while.sh
1...
2...
done............
# break 2一次性跳出两层,直接到最外层done后面
'break 2 让程序干净利落地收工'
Note

✅️ break → 跳出当前循环体,回到上一层 ✅️ exit → 终止整个脚本进程,不管嵌套多深

📌 关键区分break 跳出循环,exit 退出脚本


猜数字游戏#

Tip

RANDOM 随机数

RANDOM 是 bash 内置变量,生成 0-32767 之间的随机整数

Terminal window
1)生成1-100的随机数
[root@shell ~]#echo $((RANDOM))
17937
# RANDOM范围是0-32767
[root@shell ~]# echo $((RANDOM))
27566
[root@shell ~]#echo $((RANDOM%100+1))
86
# %100取余得到0~99,+1得到1~100
'$((RANDOM%N+M)) 生成M到M+N-1之间的随机整数'

🌰 带计数器版

2)带计数器——统计猜了几次
[root@shell ~]#cat ran.sh
#!/bin/bash
run=$(($RANDOM%100+1)) # 先随机生成一个1-100的目标数
while true; do
let i++ # 每次循环计数器+1
read -p "请输入你要猜的数字(1-100):" num
if [ "$num" -gt "$run" ]; then
echo "猜大了~"
elif [ "$num" -lt "$run" ]; then
echo "猜小了~"
else
echo "总共猜了${i}次, 🎉恭喜你终于猜对了~"
exit
fi
done
# let i++ 整数运算,自增计数器,统计循环次数
✅️ 猜对时打印累计次数
# 三种分支:大了、小了、猜对了
'猜对就exit退出,游戏结束'

ping脚本#

[root@shell ~]#cat ping.sh
#!/bin/bash
ping -c2 -W2 $1 &>/dev/null
# -c2: 只发2个包 -W2: 超时1秒
if [ $? -eq 0 ];then
echo $1 在线.....
else
echo $1 不在线...
fi
[root@shell ~]# bash ping.sh www.baidu.com
www.baidu.com 在线.....
[root@shell ~]# bash ping.sh wwwww.basifasdfasdf.com
wwwww.basifasdfasdf.com 不在线...
'ping -c2 -W2 控制发包数和超时,避免脚本卡住'

case语句#

📌 类似 if,是流程控制语句,用于多分支匹配

语法结构#

Terminal window
case 变量 in # 变量来源: 直接传参、赋值传参、read接收、脚本定义
匹配序列1)
命令集
;;
匹配序列2)
命令集
;;
匹配序列3)
命令集
;;
*)
echo "Usage: $0 参数1|参数2"
esac
# ) 匹配序列后跟右括号
# ;; 每个分支结束必须双分号
# *) 通配符,匹配所有其他情况,类似default
# esac case的反写,结束标志 ⭕

🌰 基础示例

[root@shell ~]#cat case.sh
#!/bin/bash
case $1 in
shell)
echo shell.........
;;
mysql)
echo mysql.........
;;
nginx)
echo nginx........
;;
*)
echo "Usage: $0 [shell|mysql|nginx]"
# 这里用双引号括起来
esac
# $1是脚本的第一个参数,case根据参数值分发到对应分支
'最简单的case——传什么参数就执行什么分支'

案例1:系统信息查看脚本#

case + while 实现交互式菜单,循环接收用户输入

1)系统信息查看菜单
[root@shell ~]#cat case.sh
#!/bin/bash
men(){
echo -e "\e[34m\t\t(1)查看内存\e[0m"
echo -e "\e[34m\t\t(2)查看磁盘\e[0m"
echo -e "\e[34m\t\t(3)查看负载\e[0m"
echo -e "\e[34m\t\t(4)显示主菜单\e[0m"
echo -e "\e[34m\t\t(exit)退出~\e[0m"
}
men
# 先调用一次函数 --> 显示菜单
while true
do
read -p "输入后~查看对应系统编号[(4)显示菜单]: " num
case $num in
1)
free -h
;;
2)
df -h
;;
3)
uptime
;;
4)
men # 重新显示菜单
;;
exit)
exit
;;
*)
echo "Usage: $0 [1|2|3|4]"
esac
done
# men()函数封装菜单显示,避免在循环里重复写echo
# case根据用户输入执行对应命令,选4重显菜单
'函数定义菜单→while死循环等待输入→case匹配执行'
✅️ 经典组合: while + case + 函数
Tip

💡 men() 函数封装菜单显示,定义一次,多处调用——这就是函数的意义


案例2:Nginx启动脚本#

Terminal window
1)确认nginx路径
[root@web ~]#which nginx
/usr/sbin/nginx
[root@web ~]#/usr/sbin/nginx # 启动
[root@web ~]#/usr/sbin/nginx -s stop # 停止
[root@web ~]#/usr/sbin/nginx -s reload # 重新加载
[root@web ~]#/usr/sbin/nginx -s stop && sleep 1 && /usr/sbin/nginx # 重启
# restart: 先stop,sleep 1秒等进程结束,再start
nginx通过-s参数控制: stop停止、reload重载、stop+sleep+start=重启
========================================
小bug🐛 --> 如果nginx处于停止状态,-s stop 会报错
root@Ubuntu ~# nginx -s stop
root@Ubuntu ~# ss -lntup | grep nginx | wc -l
0
root@Ubuntu ~# /usr/sbin/nginx -s stop && sleep 1 && /usr/sbin/nginx
nginx: [error] open() "/run/nginx.pid" failed (2: No such file or directory)
# 本来就没有运行,没有办法关闭 ❌ --> 后面也Nginx也启动不起来~
root@Ubuntu ~# ss -lntup | grep nginx | wc -l
0
'优化后'
root@Ubuntu ~# /usr/sbin/nginx -s stop 2>/etc/null; sleep 1 && /usr/sbin/nginx
# 吞掉报错 --> ;无论是否成功继续启动Nginx
root@Ubuntu ~# echo $?
0 说明上一条命令执行成功
root@Ubuntu ~# ss -lntup | grep nginx | wc -l
1 服务启动成功
========================================
2)Nginx启动脚本
'加执行结果反馈(加成功/失败提示)'
# 避免重复代码
[root@web ~]#cat nginx.sh
#!/bin/bash
ac=$1
# 在函数外 $1 是脚本的第一个参数
# 把$1先存到变量,方便函数内引用
te(){
if [ $? -eq 0 ];then
echo -e "\e[32m Nginx $ac 成功✅\e[0m"
else
echo -e "\e[31m Nginx $ac 失败❌\e[0m"
fi
}
case $ac in
start)
/usr/sbin/nginx
te
;;
stop)
/usr/sbin/nginx -s stop
te
;;
reload)
/usr/sbin/nginx -s reload
te
;;
restart)
/usr/sbin/nginx -s stop 2>/etc/null; sleep 1 && /usr/sbin/nginx
te
;;
status)
nginx_re=`ps axu|grep "nginx: master"|grep -v grep|wc -l`
[ $nginx_re -eq 0 ] && echo "nginx未运行❌" || echo "Nginx运行中ing✅"
# 通过过滤 nginx 的主进程,来判断nginx是否在运行
# 等于0,说明主进程没有启动起来~
# grep -v grep排除grep自身进程,不然统计会多1
;;
*)
echo "Usage: $0 [start|stop|restart|reload|status]"
esac
# te()把重复的成功/失败判断封装起来,每个分支只需调用一行te
✅️ 函数可以访问外部变量$ac——函数内外不是完全隔离的
✅️ status分支逻辑不同,不需要TE,保持独立即可

案例3:case或判断表达式#

case 支持 | 匹配多个值

1)用if -o实现或判断
[root@shell ~]#cat jumpserver.sh
#!/bin/bash
web=10.0.0.7
WEB02=10.0.0.8
DB01=10.0.0.51
men(){
echo -e "\e[34m\t\t\t\t\t1.web\e[0m"
echo -e "\e[34m\t\t\t\t\t2.WEB02\e[0m"
echo -e "\e[34m\t\t\t\t\t3.DB01\e[0m"
}
men
read -p "输入连接的服务器编号或者IP地址或者主机名称" num
if [ $num = 1 -o $num = web -o $num = 10.0.0.7 ];then
# 这里必须用的是字符串匹配,-eq只能用于整数
# 如果输入的是 web -eq 1 会报错的~
echo hehe
fi
# -o 表示or,多个条件有一个成立即可
'if用-o写多个or条件,但多了可读性差'
========================================
2)用case | 实现——更优雅
========================================
[root@shell ~]#cat jumpserver.sh
# ...变量定义和men1函数同上...
read -p "输入连接的服务器编号或者IP地址或者主机名称" num
case $num in
1|web|10.0.0.7)
echo web...........
;;
2|WEB02|10.0.0.8)
echo web02......
;;
esac
# case中用|分隔多个匹配值,比if -o直观太多
✅️ case + | 是写多条件匹配的首选方式

案例4:跳板机脚本#

1)基础跳板机
[root@shell ~]#cat jumpserver.sh
#!/bin/bash
web=172.16.1.7
WEB02=172.16.1.8
DB01=172.16.1.51
men1(){
echo -e "\e[34m\t\t\t\t\t1.web\e[0m"
echo -e "\e[34m\t\t\t\t\t2.WEB02\e[0m"
echo -e "\e[34m\t\t\t\t\t3.DB01\e[0m"
}
men1
read -p "输入连接的服务器编号或者IP地址或者主机名称" num
case $num in
1|web)
ssh $web
;;
2|WEB02)
ssh $WEB02
;;
esac
========================================
2)免密登录准备——先和客户端做免密钥
========================================
[root@shell ~]#ssh-keygen # 服务端生成密钥对
[root@shell ~]#ssh-copy-id 172.16.1.8
[root@shell ~]#ssh-copy-id 172.16.1.7
# 免密后ssh直接连,不弹密码框

完善版跳板机——角色+密码+验证码#

1)完善后的jumpserver
[root@shell ~]#cat jumpserver.sh
#!/bin/bash
web=172.16.1.7
WEB02=172.16.1.8
DB01=172.16.1.51
role(){
echo -e "\e[33m\t\t\t\t\t1.运维\e[0m"
echo -e "\e[33m\t\t\t\t\t2.开发\e[0m"
}
role
men1(){
echo -e "\e[34m\t\t\t\t\t1.web\e[0m"
echo -e "\e[34m\t\t\t\t\t2.WEB02\e[0m"
echo -e "\e[34m\t\t\t\t\t3.DB01\e[0m"
}
men2(){
echo -e "\e[34m\t\t\t\t\t1.web\e[0m"
}
trap "" HUP TSTP INT
# 屏蔽Ctrl+C等信号,防止用户退出脚本
read -p "请输入你的角色: " num
if [ $num -eq 1 ];then # 运维——可管理所有主机
while true
do
read -p "请输入你的密码: " pass
if [ $pass -eq 123 ];then
break
else
let i++
echo "你输入密码不正确、请重新输入"
[ $i -eq 3 ] && echo 密码错误次数过多,请稍后再试 && sleep 5
if [ $i -eq 5 ];then
read -p "密码次数过多请输入你的微信账号: " wx
ran=`echo $((RANDOM))|md5sum|cut -c 1-8`
echo 验证码已发送到$wx
python2.7 weixin.py "$wx" "验证码" "$ran"
read -p "请输入接收到的验证码: " ra
if [ $ra = $ran ];then
python2.7 weixin.py "$wx" "密码" "123"
unset i
continue
else
echo hehe
fi
fi
fi
done
men1
while true
do
read -p "输入连接的服务器编号[p输出主机列表]: " num
case $num in
1|web)
ssh $web
;;
2|WEB02)
ssh $WEB02
;;
p)
men1
;;
esac
done
elif [ $num -eq 2 ];then # 开发——只能连web
men2
while true
do
read -p "输入连接的服务器编号[p输出主机列表]: " num
case $num in
1)
ssh $web
;;
p)
men2
;;
esac
done
fi
# 运维角色:输密码→最多3次重试→5次锁住→微信验证码解锁→显示运维菜单
# 开发角色:直接显示开发菜单,只能连web
'用角色控制权限——运维看全菜单,开发只看一台机器'
⚠️ trap屏蔽信号防止Ctrl+C退出,要预留后门: woshiyunwei→exit
Important

📌 跳板机核心设计

  • ① 角色分离——运维 vs 开发,菜单不同
  • ② 密码验证——3次错误锁5秒,5次错误发微信验证码
  • ③ trap 屏蔽信号——防止 Ctrl+C 直接退出
  • ④ 预留后门——woshiyunwei)exit

for循环#

语法结构#

Terminal window
for i in 取值列表
do
命令集合
done
# i 是循环变量,每次从取值列表中取一个值
# 取值列表可以是: 字符串、数字、序列、命令、变量

案例1:循环数字#

Terminal window
1)直接写数字列表
[root@shell ~]#cat for.sh
for i in 1 2 10
do
echo $i
done
[root@shell ~]#sh for.sh
1
2
10
# 数字以空格分隔,for按空格取值

案例2:循环字符串#

Terminal window
2)循环字符串
[root@shell ~]#cat for.sh
for i in a b c
do
echo $i
done
[root@shell ~]#sh for.sh
a
b
c
# 字符串同样按空格分隔

案例3:支持序列#

Terminal window
3)数字序列 {1..10}
[root@shell ~]#cat for.sh
for i in {1..10}
do
echo $i
done
[root@shell ~]#sh for.sh
1
2
3
4
5
6
7
8
9
10
# {1..10} 自动展开为1到10的序列
========================================
4)字母序列 {a..d}
========================================
[root@shell ~]#cat for.sh
for i in {a..d}
do
echo $i
done
[root@shell ~]#sh for.sh
a
b
c
d
'{a..d} 字母序列也能展开,好用'

案例4:支持命令#

取值列表可以来自命令的输出——用反引号 `$() 包裹

Terminal window
5)seq命令生成序列
[root@shell ~]#cat for.sh
read -p "请输入数字: " num
for i in `seq $num`
do
echo $i
done
[root@shell ~]#sh for.sh
请输入数字: 5
1
2
3
4
5
# seq $num 动态生成1到$num的序列
========================================
6)cat命令读取文件
========================================
[root@shell ~]#cat for.sh
for i in `cat 1.txt`
do
echo $i
done
[root@shell ~]#cat 1.txt
zhangsan
lisi
[root@shell ~]#sh for.sh
zhangsan
lisi
# cat 1.txt的输出作为取值列表
'命令结果也能当列表——for的取值来源非常灵活'

案例5:支持拼接#

Terminal window
7)变量拼接
[root@shell ~]#cat for.sh
for i in {1..3}
do
echo a$i
done
[root@shell ~]#sh for.sh
a1
a2
a3
# 循环体内可以用变量$i做各种拼接

案例6:批量创建用户#

Terminal window
8)批量创建用户——基础版
[root@shell ~]#cat for.sh
for i in {1..3}
do
useradd oldboy$i
done
# 循环三次,创建oldboy1、oldboy2、oldboy3
========================================
9)批量创建用户——灵活版(输入前缀和个数)
========================================
[root@shell ~]#cat for.sh
read -p "请输入用户前缀: " prefix
read -p "请输入用户个数: " num
for i in `seq $num`
do
user=$prefix$i
echo $user
done
read -p "[y创建用户|d删除用户]" num1
for a in `seq $num`
do
case $num1 in
y)
user=$prefix$a
id $user &>/dev/null
if [ $? -eq 0 ];then
echo "$user 用户已存在"
else
useradd $user &>/dev/null
[ $? -eq 0 ] && echo $user创建成功
fi
;;
d)
user=$prefix$a
id $user &>/dev/null
if [ $? -eq 0 ];then
userdel -r $user
[ $? -eq 0 ] && echo $user删除成功
else
echo "$user 用户不存在"
fi
;;
esac
done
# 先输入前缀和个数预览用户名,再选择y创建或d删除
'id检查用户是否存在→存在跳过/不存在创建'
✅️ 创建前先预览,确认后再操作——安全操作的好习惯

案例7:批量探测IP是否在线#

笔试题经典:探测 10.0.0.1-254 的 IP 地址是否在线

1)并发ping探测
[root@shell ~]#cat ping.sh
#!/bin/bash
for i in `seq 254`
do
{
ip=10.0.0.$i
ping -c1 -W1 $ip &>/dev/null
if [ $? -eq 0 ];then
echo $ip 在线...
fi
} &
done
wait
echo 探测完成.....
# {} & 每个ping放进后台并发执行,254个同时跑
# wait 等待所有后台进程结束后再继续
'不用{}&,254个IP顺序ping要等很久——并发才是王道'
✅️ 后台并发 + wait等待 = 快速批量ping

案例8:从文件读取创建用户#

2)从文件批量创建用户
[root@shell ~]#cat user.sh
#!/bin/bash
for i in `cat 1.txt`
do
useradd $i
done
[root@shell ~]#cat 1.txt
zhangsan
lisi
laowang
# 用户列表写在文件里,for循环逐行读取创建

案例9:给每个用户设置随机密码#

Terminal window
3)创建用户并设随机密码
[root@shell ~]#cat for.sh
read -p "请输入用户前缀: " prefix
read -p "请输入用户个数: " num
for i in `seq $num`
do
user=$prefix$i
echo $user
done
read -p "[y创建用户|d删除用户]" num1
for a in `seq $num`
do
case $num1 in
y)
user=$prefix$a
id $user &>/dev/null
if [ $? -eq 0 ];then
echo "$user 用户已存在"
else
useradd $user &>/dev/null
[ $? -eq 0 ] && echo $user创建成功
echo $user >> pass.txt
echo `mkpasswd`|tee -a pass.txt|passwd --stdin $user
fi
;;
d)
user=$prefix$a
id $user &>/dev/null
if [ $? -eq 0 ];then
userdel -r $user
[ $? -eq 0 ] && echo $user删除成功
else
echo "$user 用户不存在"
fi
;;
esac
done
# mkpasswd生成随机密码串→tee记录到pass.txt→passwd --stdin设给用户
'mkpasswd生成随机密码,tee一边记密码本一边设密码'
✅️ 密码记录到pass.txt方便后续分发
Warning

🤡 生产环境记得保管好 pass.txt,或者用完就删


命令行一行for#

Terminal window
# 命令行快速循环——适合临时批量操作
[root@shell ~]#for i in `seq 5`;do echo $i;done
1
2
3
4
5
[root@shell ~]#for i in `seq 5`;do echo old$i;done
old1
old2
old3
old4
old5
# 批量建用户——一行搞定
[root@shell ~]#for i in `seq 5`;do useradd old$i;done
[root@shell ~]#tail -5 /etc/passwd
old1:x:1014:1014::/home/old1:/bin/bash
old2:x:1015:1015::/home/old2:/bin/bash
old3:x:1016:1016::/home/old3:/bin/bash
old4:x:1017:1017::/home/old4:/bin/bash
old5:x:1018:1018::/home/old5:/bin/bash
# 批量删——也是一行
[root@shell ~]#for i in `seq 5`;do userdel -r old$i;done
# 命令行for循环是运维的瑞士军刀
'一行建5个,一行删5个——简洁高效'

案例10:100内能被3整除的数的和#

Terminal window
1)执行过程分析
for i in `seq 100`
# i=1: 1%3=1 不等于0 跳过
# i=2: 2%3=2 不等于0 跳过
# i=3: 3%3=0 count=$[0+3]=3
# i=4: 4%3=1 不等于0 跳过
# i=5: 5%3=2 不等于0 跳过
# i=6: 6%3=0 count=$[3+6]=9
# ...以此类推...
========================================
2)完整脚本
========================================
[root@shell ~]#cat count.sh
#!/bin/bash
for i in `seq 100`
do
num=`echo $[$i%3]` # $i%3 取余数
if [ $num -eq 0 ];then
count=$[$count+$i] # 余数为0则累加
fi
done
echo $count
[root@shell ~]#sh count.sh
1683
# 100以内能被3整除的数: 3,6,9,...,99 总和1683

案例11:for循环从1加到100#

Terminal window
[root@shell ~]#cat c.sh
for i in `seq 100`
do
count=$[count+i]
done
echo $count
[root@shell ~]#sh c.sh
5050
# 经典的累加——for循环的最佳练手题


while循环#

语法结构#

Terminal window
while [ 条件表达式 ] # 成立则执行、不成立不执行
do
命令集合
done

📌 和 if 一样用 [ ] 条件表达式,条件成立才进入循环体

案例1:死循环的两种写法#

Terminal window
1)while true
while true
do
echo hehe
done
# true永远为真→死循环
========================================
2)while [ 条件恒成立 ]
========================================
while [ 10 -eq 10 ]
do
echo hehe
done
# 10永远等于10→也是死循环
'两种写法等效,while true更常用'

案例2:循环序列(while版)#

1)while实现1到100
[root@shell ~]#cat while.sh
#!/bin/bash
i=1
while [ $i -le 100 ]
do
echo $i
let i++
done
# while版需要自己维护计数器:初始值i=1,每次let i++,条件i<=100
'while不像for自动取序列——需要手动管理变量和条件'

案例3:从1加到100(while版)#

[root@shell ~]#cat while.sh
#!/bin/bash
i=1
while [ $i -le 100 ]
do
c=$[c+i]
let i++
done
echo $c
[root@shell ~]#sh while.sh
5050
# 同样的累加逻辑,while版三步:初始化i→循环累加→自增

案例4:for vs while 读取文件的关键区别#

Terminal window
1)准备测试文件
[root@shell ~]#cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
# /etc/hosts每行有多个字段,空格分隔
========================================
2)for循环——按空格分隔
========================================
[root@shell ~]#cat while.sh
#!/bin/bash
for i in `cat /etc/hosts`
do
echo $i
done
[root@shell ~]#sh while.sh
127.0.0.1
localhost
localhost.localdomain
localhost4
localhost4.localdomain4
::1
localhost
localhost.localdomain
localhost6
localhost6.localdomain6
# for按空格和换行符切分,每个词单独一行
'for循环:见到空格就切一刀——不管原来是不是一行'
========================================
3)while read——按行读取
========================================
[root@shell ~]#cat while.sh
#!/bin/bash
while read line
do
echo $line
done</etc/hosts
[root@shell ~]#sh while.sh
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
# while read 逐行读取,保留每行的原始格式
'while read:一行就是一整行——空格不动'

📌 核心区别for 按空格分隔值,while read 按行读取——读文件内容时 while read 更准确

案例5:基于文件批量创建用户和密码#

Terminal window
1)准备用户密码文件
[root@shell ~]#cat 1.txt
zhangsan test.oldboy123.com
lisi old.123.com
laowang hehe.123.com
# 每行:用户名 密码
========================================
2)while read 逐行处理
========================================
[root@shell ~]#cat while.sh
#!/bin/bash
while read line
do
user=`echo $line|awk '{print $1}'`
pass=`echo $line|awk '{print $2}'`
useradd $user &>/dev/null
[ $? -eq 0 ] && echo $user 创建成功
echo $pass|passwd --stdin $user
done<1.txt
# read读每一行→awk取第1列用户名、第2列密码→创建用户并设密码
'done < 1.txt 把文件重定向到while循环的标准输入'
✅️ while read + awk 是处理格式化文件的经典组合

流程控制:break continue exit#

Terminal window
1)exit——直接退出脚本
========================================
[root@shell ~]#useradd old3
# 先让old3存在,触发exit分支
[root@shell ~]#cat while.sh
#!/bin/bash
for i in {1..5}
do
user=old$i
id $user &>/dev/null
if [ $? -eq 0 ];then
exit # 直接退出脚本
else
useradd $user &>/dev/null
[ $? -eq 0 ] && echo $user创建成功
fi
done
echo 执行完成.......
[root@shell ~]#sh while.sh
old1创建成功
old2创建成功
# old3已存在→触发exit→脚本直接终止→最后的echo没执行
'exit是核武器——不管在哪层,直接结束整个进程'
========================================
2)break——跳出循环继续执行
========================================
[root@shell ~]#for i in `seq 2`;do userdel -r old$i;done
# 清理old1和old2
[root@shell ~]#cat while.sh
#!/bin/bash
for i in {1..5}
do
user=old$i
id $user &>/dev/null
if [ $? -eq 0 ];then
break # 跳出循环继续执行
else
useradd $user &>/dev/null
[ $? -eq 0 ] && echo $user创建成功
fi
done
echo 执行完成.......
[root@shell ~]#sh while.sh
old1创建成功
old2创建成功
执行完成.......
# old3已存在→触发break→跳出for循环→继续执行echo
'break是退出当前循环——脚本还活着,echo照常执行'
========================================
3)continue——跳过本次,继续下一次
========================================
[root@shell ~]#for i in `seq 2`;do userdel -r old$i;done
[root@shell ~]#sh while.sh
old1创建成功
old2创建成功
old4创建成功
old5创建成功
执行完成.......
# old3存在→触发continue→跳过old3的创建→继续old4、old5
'continue是跳过当前这一轮——下一轮照常跑'
# old3被跳过了,但old4和old5正常创建
命令作用影响范围
exit直接终止整个脚本整个进程
break跳出当前循环体当前循环
continue跳过本次循环,继续下一次当前循环的本次迭代

项目练习#

Tip

① 写过的项目都需要加上判断:

  • 判断传参不能为空
  • 判断必须为整数
  • 判断必须连续的字符串

② 中午吃啥?随机生成一个——用 RANDOM + case 实现

③ 老男孩大饭店——二级菜单 + 会员系统 + 结账

④ 大酒店服务——菜单 + 服务 + 价格 + 会员 + 消费 + 余额

⑤ 双色球——随机数生成 + 数组统计

📌 这些项目将 while + case + for + 函数 + 数组综合运用,是检验学习成果的好练习



小结#

知识点核心要点
while条件循环,while true = 死循环,配合 break / exit 退出
break N跳出 N 层循环,默认 = break 1
exit直接退出整个脚本,不管嵌套多深
continue跳过本次循环,继续下一次
case多分支匹配,| 连接多值,;; 结束分支,*) 通配,esac 结束
for i in 列表取值列表支持:字符串、数字、{1..10} 序列、`命令`、变量
for vs while readfor 按空格分隔,while read 按行读取
{} & + wait后台并发 + 等待所有结束——批量任务加速
let i++整数自增,等效 ((i++)),常用于计数器
RANDOMbash 内置随机数,范围 0-32767,$((RANDOM%100+1)) 生成 1-100
$?上一条命令返回值,0 = 成功,非0 = 失败
trap "" HUP TSTP INT屏蔽信号,防止 Ctrl+C 退出脚本
/etc/init.d/functions系统函数库,action 美化输出 [ OK ] / [FAILED]
Important

📌 三种循环各自适用场景

  • for —— 知道循环次数 / 遍历列表 / 批量操作
  • while —— 条件判断式循环 / 逐行读文件 / 死循环+break
  • case —— 多分支分发 / 服务管理脚本 / 菜单路由

📌 代码进化思路:基础实现 → 加状态反馈 → 抽函数去冗余 → 用系统库美化

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

循环与case多分支
https://www.kpyun.fun/posts/automation/shell/shell03/
作者
久棹
发布于
2026-06-28
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
久棹
只要胆子大,天天寒暑假!
公告
欢迎来到久棹的技术小站!本站专注 Linux 运维学习笔记分享,如有问题欢迎交流探讨 🎉
分类
标签
站点统计
文章
98
分类
11
标签
203
总字数
244,453
运行时长
0
最后活动
0 天前
站点信息
构建平台
Local
博客版本
Firefly v6.13.5
文章许可
CC BY-NC-SA 4.0

文章目录