Shell 无限循环和指定次数循环
《Shell 无限循环和指定次数循环》深度学习版 🧠
🎉 欢迎来到 Shell 编程中非常实用的一章 —— 无限循环与指定次数循环。它们是自动化任务、监控系统状态、实现定时操作等场景的必备技能。掌握它,你就能写出真正“永不停歇”或“精准执行”的脚本!
🎯 学习目标
- 理解无限循环与有限次循环的基本原理
- 掌握
while true、for (( ))、seq、eval等多种方式实现循环 - 能在实际脚本中灵活使用监控、定时检查、批量处理等场景
- 学会结合
sleep、break、continue控制循环流程 - 避免常见陷阱和语法错误,写出健壮可靠的 Shell 循环语句
⭐ 核心重点(知识点速览)
| 类型 | 内容 | 描述 |
|---|---|---|
| 无限循环 | while true; do ... done |
条件永远为真时持续运行 |
| 指定次数循环 | for ((i=1; i<=N; i++)); do ... done |
执行固定次数 |
| 命令生成序列 | seq, eval, {1..n} |
快速生成数字范围 |
| 实时监控 | tail -f, ping, ps |
结合 while 实现实时输出 |
| 定时任务 | sleep N |
控制循环间隔时间 |
| 控制结构 | break, continue |
控制循环流程 |
| 不同 shell 差异 | bash vs dash | 注意兼容性问题 |
📖 详细讲解
一、无限循环(Infinite Loop)🔥
适用于需要持续运行的任务,如守护进程、日志监控、定时检查等。
✅ 示例:每秒显示系统负载
while true
do
load=$(uptime | awk '{print $10}')
echo "[$(date +"%T")] 当前系统负载:$load"
sleep 1
done
💡 这是最基本的“永动”模式,常用于后台服务监听。
二、退出无限循环的方式 🛑
虽然叫“无限”,但大多数情况下我们都需要一种方式来退出循环。
✅ 示例:按 Ctrl+C 终止 或 使用 break
while true
do
read -p "请输入 quit 退出:" input
if [ "$input" = "quit" ]; then
echo "👋 正在退出..."
break
else
echo "🔁 请再试一次"
fi
done
三、使用 until 实现“直到满足条件才停止”的循环 🕒
until 是 while 的反向版本,当条件不成立时继续循环,成立时退出。
✅ 示例:等待文件出现后退出
target_file="/tmp/ready.txt"
echo "⏳ 正在等待文件 $target_file 出现..."
until [ -f "$target_file" ]
do
sleep 1
done
echo "✅ 文件已找到!继续执行后续操作..."
四、指定次数循环 🔁
适用于只需要执行固定次数的任务,如模拟进度条、定时提醒、测试等。
✅ 方法 1:C 风格 for 循环(Bash 特有)
for ((i=1; i<=5; i++))
do
echo "第 $i 次循环"
done
✅ 方法 2:使用 seq 命令(POSIX 兼容)
for i in $(seq 1 5)
do
echo "第 $i 次循环"
done
✅ 方法 3:使用花括号展开(Bash 特有)
for i in {1..5}
do
echo "第 $i 次循环"
done
✅ 方法 4:使用 eval 动态生成(高级技巧)
n=5
for i in $(eval echo "{1..$n}")
do
echo "第 $i 次循环"
done
五、实战案例分析 🧪
🎯 场景一:带进度条的安装模拟器
for i in {1..10}
do
percent=$((i * 10))
bar=$(printf '=%.0s' $(seq 1 $i))
printf "\r[%-10s] %d%% " "$bar" "$percent"
sleep 0.5
done
printf "\n✅ 安装完成\n"
💡 输出效果:
[==========] 100% ✅ 安装完成
🎯 场景二:定时清理临时文件夹 🗑️
log_file="/var/log/cleaner.log"
timestamp=$(date "+%Y-%m-%d %T")
echo "[$timestamp] 开始定时清理 /tmp 下的 .tmp 文件..." >> "$log_file"
while true
do
count=0
for file in /tmp/*.tmp
do
rm -f "$file"
count=$((count + 1))
done
echo "[$(date "+%T")] 共删除 $count 个临时文件" >> "$log_file"
sleep 60 # 每分钟清理一次
done
🎯 场景三:自动重启宕机的服务 🔄
service_name="nginx"
while true
do
if systemctl is-active --quiet "$service_name"; then
echo "[$(date "+%T")] $service_name 正常运行"
else
echo "🔴 $service_name 已宕机,正在尝试重启..."
systemctl restart "$service_name"
if [ $? -eq 0 ]; then
echo "✅ $service_name 重启成功"
else
echo "❌ $service_name 重启失败,请人工介入"
fi
fi
sleep 10
done
🎯 场景四:用户登录验证限制重试次数 🔐
max_attempts=3
valid_user="admin"
valid_pass="password"
for attempt in $(seq 1 $max_attempts)
do
read -p "请输入用户名:" username
read -sp "请输入密码:" password
if [ "$username" = "$valid_user" ] && [ "$password" = "$valid_pass" ]; then
echo -e "\n✅ 登录成功!欢迎 $username"
exit 0
else
remaining=$((max_attempts - attempt))
echo -e "\n❌ 登录失败,剩余尝试次数:$remaining"
fi
done
echo "🚫 登录失败次数过多,程序退出"
exit 1
六、不同系统的差异与注意事项 ⚠️
| 项目 | Bash | Dash (Ubuntu 默认) | zsh |
|---|---|---|---|
支持 (( )) |
✅ | ❌ | ✅ |
支持 seq |
✅ | ✅ | ✅ |
支持 {1..n} |
✅ | ❌ | ✅ |
| 推荐脚本开头 | #!/bin/bash |
#!/bin/sh |
#!/bin/zsh |
| 注意子 shell 变量作用域 | 是 | 是 | 是 |
📝 小贴士:
- 在 Ubuntu 中默认
/bin/sh是dash,不支持某些高级特性,建议脚本开头写成#!/bin/bash。 - 使用双引号包裹变量,防止路径含空格出错。
- 多层循环建议用缩进保持可读性。
⚠️ 常见陷阱 & 解决方案
| 问题 | 原因 | 解决方法 |
|---|---|---|
| 循环未执行 | 条件一开始就不成立 | 加入调试输出或初始值设置 |
| 循环无法退出 | 条件永远为真 | 使用 break 或合理修改条件 |
| 数字范围错误 | 变量未定义或非整数 | 使用 [[ $var =~ ^[0-9]+$ ]] 判断 |
| 性能问题 | 高频率调用外部命令 | 合理调整间隔时间或合并处理逻辑 |
| 循环变量未更新 | 忘记递增计数器 | 添加 i=$((i+1)) |
🧠 总结与小贴士
| 技巧 | 说明 |
|---|---|
while true 是 Shell 的“永动机” |
让脚本能持续响应变化 |
for (( )) 更适合数值范围控制 |
Bash 特有功能 |
seq 和 {1..n} 是批量处理利器 |
提升灵活性 |
| 始终对变量加双引号 | 防止空格或未定义变量出错 |
使用 sleep 控制节奏 |
避免 CPU 占用过高 |
结合 break 实现优雅退出 |
提升脚本健壮性 |
| 注意子 shell 变量作用域 | 特别是在管道中使用时 |
📚 推荐练习题(可选)
- 编写一个脚本,每隔 5 秒检查一次磁盘空间,如果超过 90%,则发送邮件通知。
- 写一个脚本,实时监控
/var/log/auth.log,发现 SSH 登录失败超过 5 次就报警。 - 实现一个脚本,不断读取用户输入的数字,并累加求和,输入
q时退出。 - 编写一个脚本,模拟进度条动画(使用
\r和sleep)。 - 创建一个备份脚本,当检测到指定目录中有新文件时,自动打包上传至远程服务器。
🎯 下一章预告:《Shell 函数 Function》
你已经掌握了如何让脚本“循环执行”,下一步我们将学习如何将常用代码块封装成函数,提高复用性和可维护性 —— Shell 函数,让你的脚本更模块化、更专业!
需要我继续为你生成下一章内容吗?😊

浙公网安备 33010602011771号