Shell while 语句
《Shell while 语句》深度学习版 🧠
🎉 欢迎来到 Shell 编程中极为关键的一章 —— while 循环。它是 Linux Shell 脚本中最常用的条件循环结构,是实现“持续监听、实时处理”的核心工具。掌握它,你就能写出真正智能、自动化的脚本!
🎯 学习目标
- 理解
while循环的基本语法与执行流程 - 掌握如何用
while实现无限循环、读取输入流、监控状态等场景 - 能在实际脚本中灵活使用文件、变量、命令返回值作为判断条件
- 学会结合
read,tail -f,ps,grep等命令进行实时监控 - 避免常见陷阱和语法错误,写出健壮可靠的 Shell 条件循环语句
⭐ 核心重点(知识点速览)
| 类型 | 内容 | 描述 |
|---|---|---|
| 基本语法 | while condition; do ... done |
条件为真时持续执行循环体 |
| 条件类型 | 变量、命令、test 表达式 | 控制循环是否继续 |
| 无限循环 | while true; do ... done |
用于后台服务或监控 |
| 输入流处理 | while read line; do ... done < file |
逐行读取文件或管道 |
| 实时监控 | tail -f, ping, ps 等 |
结合 while 实现实时输出 |
| 控制结构 | break, continue |
控制循环流程 |
| 不同 shell 差异 | bash vs dash | 注意兼容性问题 |
📖 详细讲解
一、基本语法结构
while condition
do
# 循环体
done
只要 condition 的退出状态码为 0(即为真),循环就会一直执行。
二、简单示例:数字递增计数器
✅ 示例:打印从 1 到 5 的数字
i=1
while [ $i -le 5 ]
do
echo "当前数字:$i"
i=$((i + 1))
done
💡 这是最基础的数值控制方式,常用于有限次循环任务。
三、无限循环(Infinite Loop)🔥
适用于需要持续运行的任务,如守护进程、日志监控、定时检查等。
✅ 示例:每秒显示系统负载
while true
do
load=$(uptime | awk '{print $10}')
echo "[$(date +"%T")] 当前系统负载:$load"
sleep 1
done
⚠️ 注意:
- 使用
Ctrl+C终止此类脚本。 - 可以加入
if判断,在满足条件时用break退出循环。
四、读取文件内容逐行处理 📄
这是最常用的数据处理技巧之一。
✅ 示例:读取用户列表并创建用户
while read user
do
if ! id "$user" &>/dev/null; then
useradd "$user"
echo "✅ 用户 $user 已创建"
else
echo "⚠️ 用户 $user 已存在"
fi
done < users.txt
💡
users.txt文件格式如下:
alice
bob
charlie
五、结合管道符读取命令输出 🔍
你可以将任意命令的输出作为 while 的输入源。
✅ 示例:列出所有正在运行的服务名称
systemctl list-units --type=service --state=running | grep -v 'Loaded' | awk '{print $1}' | while read service
do
echo "服务正在运行:$service"
done
六、实时日志监控实战 📊
✅ 示例:实时监控 Apache 日志中的 404 错误
tail -f /var/log/apache2/access.log | while read line
do
echo "$line" | grep -q " 404 "
if [ $? -eq 0 ]; then
echo "⚠️ 发现 404 错误:$line"
fi
done
💡 解释:
tail -f实时读取新增日志grep -q用于静默匹配- 如果发现 404 错误,则输出提示信息
七、等待某个事件发生 🕒
✅ 示例:等待某个文件出现
target_file="/tmp/ready.txt"
echo "⏳ 正在等待文件 $target_file 出现..."
while [ ! -f "$target_file" ]
do
sleep 1
done
echo "✅ 文件已找到!继续执行后续操作..."
八、结合 read 实现交互式菜单 🧩
✅ 示例:带退出选项的菜单
while true
do
echo "==== 主菜单 ===="
echo "1. 创建用户"
echo "2. 查看服务状态"
echo "3. 退出"
read -p "请选择操作(1-3):" choice
case $choice in
1)
read -p "请输入用户名:" new_user
useradd "$new_user" && echo "✅ 用户 $new_user 已创建"
;;
2)
systemctl status nginx
;;
3)
echo "👋 正在退出..."
break
;;
*)
echo "❌ 无效选择,请重试"
;;
esac
done
九、不同系统的差异与注意事项 ⚠️
| 项目 | Bash | Dash (Ubuntu 默认) | zsh |
|---|---|---|---|
支持 while read |
✅ | ✅ | ✅ |
支持 tail -f |
✅ | ✅ | ✅ |
支持 (( )) |
✅ | ❌ | ✅ |
| 推荐脚本开头 | #!/bin/bash |
#!/bin/sh |
#!/bin/zsh |
| 注意子 shell 变量作用域 | 是 | 是 | 是 |
📝 小贴士:
- 在 Ubuntu 中默认
/bin/sh是dash,不支持某些高级特性,建议脚本开头写成#!/bin/bash。 - 使用双引号包裹变量,防止路径含空格出错。
- 多层循环建议用缩进保持可读性。
十、实战案例分析 🧪
🎯 场景一:批量 Ping 主机并记录结果
cat << EOF > hosts.txt
web01
db01
cache01
EOF
while read host
do
ping -c 1 "$host" &>/dev/null
if [ $? -eq 0 ]; then
echo "🟢 $host 正常"
else
echo "🔴 $host 不可达"
fi
done < hosts.txt
🎯 场景二:实时监控 CPU 温度(需安装 lm-sensors)
sudo apt install lm-sensors -y
sensors | grep 'Package id 0'
while true
do
temp=$(sensors | grep 'Package id 0' | awk '{print $4}')
echo "[$(date +"%T")] CPU 温度:$temp"
sleep 1
done
⚠️ 常见陷阱 & 解决方案
| 问题 | 原因 | 解决方法 |
|---|---|---|
| 循环未执行 | 条件一开始就不成立 | 加入调试输出或初始值设置 |
| 循环无法退出 | 条件永远为真 | 使用 break 或合理修改条件 |
| 无法读取文件 | 文件不存在或权限不足 | 添加 -f 检查或 chmod 修改权限 |
| 子 shell 中变量未更新 | 在管道中赋值 | 使用全局变量或函数封装 |
| 性能问题 | 高频率调用外部命令 | 合理调整间隔时间或合并处理逻辑 |
🧠 总结与小贴士
| 技巧 | 说明 |
|---|---|
while 是 Shell 的“守望者” |
让脚本能持续响应变化 |
推荐使用 while read |
处理文本数据非常强大 |
使用 true 构建守护循环 |
适合后台监控任务 |
| 始终对变量加双引号 | 防止空格或未定义变量出错 |
结合 tail -f 实现实时监控 |
提升脚本智能化水平 |
| 避免死循环 | 合理设计退出机制 |
| 注意子 shell 变量作用域 | 特别是在管道中使用时 |
📚 推荐练习题(可选)
- 编写一个脚本,每隔 5 秒检查一次磁盘空间,如果超过 90%,则发送邮件通知。
- 写一个脚本,实时监控
/var/log/auth.log,发现 SSH 登录失败超过 5 次就报警。 - 实现一个脚本,不断读取用户输入的数字,并累加求和,输入
q时退出。 - 编写一个脚本,模拟进度条动画(使用
\r和sleep)。 - 创建一个备份脚本,当检测到指定目录中有新文件时,自动打包上传至远程服务器。
🎯 下一章预告:《Shell until 语句》
你已经掌握了如何通过 while 实现“条件为真时持续执行”,下一步我们将学习它的反向版本 —— until 循环,让你的脚本能更灵活地应对各种条件触发任务!
需要我继续为你生成下一章内容吗?😊

浙公网安备 33010602011771号