-
当你需要遍历一个已知的列表(文件、数字、字符串)时,首选
for循环。 -
当你需要在某个条件持续为真时执行任务,或读取文件时,使用
while循环。 -
当你需要等待某个条件变为真,或者逻辑上更符合“直到...才停止”的思维时,使用
until循环。 -
核心区别速览
循环类型 核心逻辑 适用场景 for循环遍历一个已知的列表或范围 处理文件列表、数字序列等明确集合中的每一个元素。 while循环当条件为“真”时执行 守护进程、读取文件、计数器循环等,条件满足则持续运行。 until循环直到条件为“真”时停止 等待某个条件成立(如等待服务启动、文件生成),条件不满足则持续运行。
1. for 循环:遍历的艺术
for 循环擅长处理已知的列表。Bash 支持多种风格。
a. 列表for循环
遍历一个明确的元素列表。
# 遍历由空格分隔的单词列表
for fruit in apple banana orange
do
echo "I like $fruit"
done

b. 使用{start..end}或seq生成序列
这是生成数字序列的常用方法。
# 使用 {起始..结束} 生成序列
for i in {1..5}
do
echo "Number: $i"
done
# 使用 seq 命令,功能更强大
for i in $(seq 1 2 10) # 从1到10,步长为2
do
echo "Odd number: $i"
done

c. 类C风格的for循环
与C语言语法类似,适合复杂的计数循环。
bash
# 初始化变量; 条件判断; 变量更新
for ((i=1; i<=5; i++))
do
echo "Counter: $i"
done

d. 遍历命令输出
这是Shell脚本中非常强大的用法。
# 遍历当前目录下的所有文件
for file in *
do
echo "Found file: $file"
done
# 遍历特定命令的输出
for user in $(cat /etc/passwd | cut -d: -f1)
do
echo "User: $user"
done

2. while 循环:条件为真时执行
while 语法规则:
while 命令; do ... done
while 会执行后面这条命令,命令返回值为 0(真)就继续循环,非 0(假)就退出。
a. while 计数器循环(数字循环,替代 for ((i;...)))
适用:需要自定义步长、循环次数、带判断的数字遍历 逻辑:手动定义计数器,循环内更新变量,条件成立就执行
i=1
while [ $i -le 5 ]
do
echo "计数:$i"
i=$((i+1)) # 计数器自增,不写就是死循环
done

- Shell:
++运算符只能放在双括号(( ))内部,单独写在赋值外面无效。
| 写法 | 是否可用 | 兼容性 |
|---|---|---|
i=$i++ | ❌ 报错 | 完全不行 |
i=$((i+1)) | ✅ 推荐 | 所有 shell 通用 |
i=$((i++)) | ✅ 可用 | bash 通用 |
((i++)) | ✅ 最简 | 仅 bash |
适用场景:分批循环处理数据、重试接口 N 次、定时循环指定次数
b. while 读取文件 / 命令输出(运维最常用!)
适用:逐行读取日志、配置、/etc/passwd、命令输出,比 for i in $(xxx) 更稳定,不会丢空格、不会撑爆内存
# 读取文件每行
while read line
do
echo "一行内容:$line"
done < /etc/passwd
# 读取管道命令输出
cut -d: -f1 /etc/passwd | while read user
do
echo "用户名:$user"
done


优势:流式读取,一行一行处理超大文件不卡顿,处理带空格的文本不会错乱,写日志分析、批量操作账号必备。
核心特点:一行一行流式读取,超大文件不卡顿,能保留空格、特殊字符
实际工作场景
- 遍历系统账号、批量操作用户 读取 /etc/passwd 批量创建家目录、修改密码、禁用闲置账号(你之前写的脚本)
- 分析日志文件 逐行过滤 nginx / 系统日志,统计报错 IP、404 请求、登录失败记录
- 批量处理配置清单 新建 ip_list.txt 存放服务器 IP,循环 ssh 批量执行命令、推送文件
txt
示例 1:过滤 /var/log/messages 系统报错日志

#!/bin/bash # 逐行读取系统日志 while read log_line do # 判断:当前行包含 error / fail 关键字 if echo "$log_line" | grep -iE "error|fail";then echo "发现异常日志:$log_line" fi # 日志文件重定向给while循环 done < /var/log/messages -
192.168.1.10 192.168.1.11 192.168.1.12while read ip do ssh root@$ip "systemctl restart nginx" done < ip_list.txt - 读取 CSV / 冒号分隔配置文件 数据库账号、业务配置按行解析,拆分字段入库
- 管道接收命令输出
docker ps | while read 容器信息,批量停止、删除过期容器
c. while 无限循环 / 死循环
两种写法:while true / while :(: 是 shell 空命令,永远返回真)
# 无限循环,靠内部 break 退出
while true
do
echo "持续运行中,输入q退出"
read input
if [ "$input" = "q" ];then
break # 跳出循环,否则永久循环
fi
sleep 1
done
适用场景:后台监控脚本、端口持续探测、菜单交互、定时轮询;
⚠️ 注意:必须加退出条件(break),否则纯死循环卡死终端。
实际工作场景
- 服务监控脚本(最常用) 持续检测 nginx、mysql 进程挂没挂,一旦停止自动重启
while true do pgrep nginx >/dev/null || systemctl start nginx sleep 3 done - 端口 / 健康状态巡检 每隔 5 秒检测业务端口通不通,异常发送告警(邮件 / 钉钉)
- 交互式菜单脚本 运维工具箱:输入数字 1 查看磁盘、2 清理日志、0 退出,循环等待用户输入
- 消息队列轮询消费 持续读取消息,有任务就处理,无任务休眠,程序 7×24 小时后台运行
- 实时同步文件 循环检测目录新文件,自动同步到备份服务器
实际工作场景:
- 接口 / 命令重试 N 次 调用 API、远程 ssh、数据库连接容易失败,最多重试 3 次就放弃,不用无限等
i=1 while ((i <= 3)) do curl http://127.0.0.1:8080/health if [ $? -eq 0 ];then break; fi echo "第$i次失败,等待2秒重试" sleep 2 ((i++)) done - 分批处理文件 / 数据 日志有 10000 行,每次只处理 100 条,分批次循环,防止一次性占满内存
- 遍历有序编号文件 文件命名 log1.log、log2.log…log20.log,按数字顺序逐个读取分析
- 定时循环固定次数 压测脚本:循环发请求 500 次后自动停止
二、三者实用度对比
- b 读取文件内容(第一实用) 运维处理日志、配置、批量遍历文件全靠它,生产脚本出现频率最高,是 while 区别于 for 循环的核心优势。
- a 计数器循环(第二实用) 当 C 风格 for 不好写复杂判断时用,比如循环失败重试 3 次、分批导出数据。
- c 无限循环(第三实用) 多用于监控、交互式菜单,不是通用遍历需求,使用场景相对窄一点。
快速选择对照表(工作时直接对照)
表格
| 场景需求 | 选用哪一种 while |
|---|---|
| 只循环固定 N 次(重试、分批、编号文件) | a 计数器循环 |
| 处理文本、日志、IP 清单、系统配置文件 | b while read 读文件 |
| 持续监控、后台常驻、交互式菜单、永久轮询 | c while true 无限循环 |
补充区分:什么时候不用 while,改用 for
- 简单数字 1~10:优先
for ((i=1;i<=10;i++)) - 匹配文件名
*.log:for file in *.log - 只要读文件、超大日志、带空格文本,一律用 while read(for 循环会出 bug)
三、补充:为什么这三类是核心,别的 while 很少用
while 的本质逻辑:判断命令返回码,返回 0(真)就执行循环体 所有 while 写法都只是「判断条件不同」衍生出来的:
- 判断数字大小 → 计数器循环 (a)
- 判断 read 读取是否成功(读到文件末尾返回假)→ 读文件 (b)
- 判断恒成立(true/:)→ 无限循环 (c)
其他小众用法(比如 while 判断文件是否存在、while 判断进程是否存活)本质上都属于无限循环的细分变种,不会单独划为一类。
四、配套区分:while 和 for 怎么选
- 简单数字序列(1~10):优先
for ((i=1;i<=10;i++)) - 逐行读文件 / 日志:必须 while read(for 有缺陷)
- 持续轮询、后台监控、交互菜单:while true 无限循环
3. until 循环:直到条件为真时停止
until 循环的逻辑与 while 相反:它会在条件测试为假(返回状态码非0)时持续执行,直到条件为真才停止
1. a:计数器循环(等价 while 计数,只是判断逻辑反过来)
单纯数字循环场景,until 完全能替代 while,只是判断条件要写反向。 示例:打印 1~5
i=1
# 直到i>5成立就停
until [ $i -gt 5 ]
do
echo $i
((i++))
done

但工作里几乎没人用 until 做纯计数,因为 while 逻辑更直观,只有为了练习语法才会这么写。
2. b:等待某个条件成立(until 真正的核心、高频实战场景)
这是 until 不可替代的优势,语义天然匹配「等待 XX 出现就停止」,可读性碾压 while 取反。 典型运维场景:
- 等待端口监听(mysql/nginx 启动)
- 等待文件生成
- 等待主机 ping 通
- 等待接口健康检查返回成功 示例:等待 3306 端口出现
until ss -lnp | grep 3306 &>/dev/null
do
echo "mysql未启动,等待2秒"
sleep 2
done
echo "mysql就绪"

补充:有没有第三种用法?
没有独立第三类,只有一个衍生用法:交互式等待输入退出,本质还是「等待条件成立(输入 q)」,属于 b 类等待场景的分支,不算独立分类。
until [ "$input" = "q" ]
do
read input
done
实操选择建议
- 单纯计数、批量遍历:只用
while/ C 风格for,不用 until; - 脚本需要等待某个资源就绪再往下执行:优先
until,代码更好看懂; - 无限常驻监控(一直跑不主动停):只用
while true,不用 until。
1万+

被折叠的 条评论
为什么被折叠?



