08-循环控制
for if 作业
循环打印1到10,完成任务
- 不打印5
- 不打印4和5
- 不打印偶数
- 不打印奇数
在 Bash 脚本中,循环控制是自动化运维任务的核心。以下是对关键循环控制结构的解释及实用案例:
一、核心循环控制结构
break
立即终止当前循环,执行循环后的代码
典型场景:满足条件时提前退出循环continue
跳过当前迭代剩余代码,进入下一次循环
典型场景:过滤不需要处理的情况while
条件为真时持续循环
典型场景:监控类任务for
遍历列表/数组执行操作
典型场景:批量处理文件/服务exit
立即终止脚本执行
典型场景:遇到致命错误时退出
二、运维脚本案例集
案例 1:服务状态监控(break + while)
根据进程pid判断进程是否挂掉
# nginx_pid=$(ps -ef |grep 'nginx: master' | grep -v 'grep' | awk '{print $2}')
#!/bin/bash
# 监控Nginx服务,若连续3次检测失败则告警并停止检测
max_retries=3
retries=0
while true; do
if systemctl is-active redis &>/dev/null; then
echo "[$(date)] redis is running"
break # 服务正常则退出监控循环
else
((retries++)) # 重试次数+1 1/3
echo "[$(date)] redis maybe down! Retry $retries/$max_retries"
# 重试次数大于等3,程序直接异常退出
if [ $retries -ge $max_retries ]; then
echo "ALERT: redis failed to start!" >&2
exit 1 # 严重故障退出脚本
fi
# 5秒重试一次
sleep 5
fi
done
案例 2:日志文件清理(continue + for)
# 注意引号区别
双引号包裹变量,禁止二次解析通配符
双引号包裹路径,通配符 * 被抑制扩展,Bash 将其视为字面字符串
命令1流程:
for循环输入 → "/var/log/*.log"(字面字符串)
↓
echo "$log" → 直接输出字符串
命令2流程:
for循环输入 → "/var/log/*.log"(字面字符串)
↓
echo $log → 替换为 /var/log/*.log → 通配符展开 → 输出真实文件列表
案例
#!/bin/bash
# 删除 /var/log 下7天前的.log文件,跳过正在使用的文件
log_dir="/var/log"
days=7
for logfile in "$log_dir"/*.log; do
if lsof "$logfile" &>/dev/null; then
echo "Skipping active file: $logfile"
continue # 跳过被占用的文件
fi
if find "$logfile" -mtime +$days -exec rm -vf {} \; &>/dev/null; then
echo "Deleted: $logfile"
fi
done
案例 3:批量用户创建(break on error)
#!/bin/bash
# 从userlist.txt批量创建用户,遇到格式错误立即终止
userfile="userlist.txt"
for line in $(cat $userfile); do
if [[ ! $line =~ ^[a-z0-9_]+$ ]]; then
echo "ERROR: Invalid username '$line'"
break # 发现非法用户名立即停止处理
fi
if id "$line" &>/dev/null; then
echo "User $line already exists"
continue # 跳过已存在用户
fi
useradd -m "$line" && echo "Created user: $line"
done
案例 4:磁盘空间监控(while + exit)
#!/bin/bash
# 检查根分区使用率,超过90%立即告警退出
threshold=90
while :; do
usage=$(df -h / | awk 'NR==2 {print $5}' | tr -d '%')
if [ $usage -ge $threshold ]; then
echo "CRITICAL: Disk usage $usage%! Sending alert..."
send_alert "Disk full" # 假设存在的告警函数
exit 2 # 立即退出并返回状态码2
else
echo "Current usage: $usage% - OK"
fi
sleep 300 # 每5分钟检测一次
done
案例 5:智能重试机制(continue + 嵌套循环)
#!/bin/bash
# 批量下载URL列表,失败后最多重试3次
urls=(
"https://example.com/file1.tar.gz"
"https://example.com/file2.iso"
"https://broken-url.com/errorfile"
)
for url in "${urls[@]}"; do
filename=$(basename "$url")
retry=0
while [ $retry -lt 3 ]; do
if wget -q --timeout=20 "$url"; then
echo "Downloaded: $filename"
break # 成功则跳出重试循环
else
((retry++))
echo "Failed $retry/3: $filename"
if [ $retry -eq 3 ]; then
echo "Permanent failure: $url" >> failed_downloads.log
continue 2 # 跳过当前文件,继续下一个URL
fi
sleep $((retry*5)) # 指数退避:5,10,15秒
fi
done
done
三、关键技巧总结
break N
:跳出N层嵌套循环continue N
:跳过N层循环的当前迭代- 循环陷阱处理:结合
trap
实现中断处理 - 性能优化:避免在循环内启动不必要的子进程
- 超时控制:结合
timeout
命令防止死循环
这些模式可灵活组合,应对服务监控、批量操作、故障处理等典型运维场景。实际使用时注意添加日志记录和错误处理机制。
1.应用场景
1. 循环我们已经从for while两大循环中感受到其方便,但很多时候我们希望中断这个循环,或者跳过某次循环
2. 例如网站的登录验证,输入允许错误三次,再就终止循环,不让登录了。
2.break
语法
break用于终止当前循环,如某一个for循环、某一个while循环
3.终止for循环
#!/bin/bash
# 到11的时候结束循环,注意,是包括11,还是不包括11?
for i in {1..20}
do
echo "$i"
if [ $i == 11 ];then
break
fi
echo "这里代码什么时候会执行呢?"
done
echo "程序结束~"
4.continue
1. 跳过本次循环,忽略本次循环的代码执行,直接进入下一次循环,直到结束。
2. 循环结束后,循环外部的代码依然继续。
打印1~20、跳过6和16
#!/bin/bash
# 到11的时候结束循环
for i in {1..20}
do
if [ $i == 6 -o $i == 16 ];then
continue
fi
echo "$i"
echo "这里代码什么时候会执行呢?"
done
echo "程序结束~"
5.exit命令
exit用于直接退出当前进程,脚本直接结束了。
打印1~20,到13的时候,程序直接结束。
#!/bin/bash
# 到11的时候结束循环
for i in {1..20}
do
if [ $i == 13 ];then
exit
fi
echo "$i"
echo "这里代码什么时候会执行呢?"
done
echo "程序结束~这一次能看到我吗?"