shell 循环(保姆级教程)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观
前言
在编程的世界中,重复执行任务是开发过程中最常见的需求之一。无论是遍历文件目录、批量处理数据,还是自动化运维操作,shell 循环都是实现这一目标的核心工具。对于编程初学者而言,理解循环的逻辑结构和语法细节,能够显著提升脚本的自动化能力;而对中级开发者来说,掌握循环的高级技巧和优化方法,则能进一步提高代码的效率和可维护性。
本文将从基础到进阶,系统讲解 shell 循环 的核心概念与应用场景,并通过实际案例和代码示例,帮助读者逐步构建对循环逻辑的直观理解。
一、循环的基础概念与核心逻辑
1.1 什么是循环?
循环(Loop)是一种控制程序流程的结构,它允许开发者在满足特定条件时,重复执行一段代码块。在 shell 脚本中,循环主要分为三类:
- 条件循环(如
while
和until
):根据条件是否成立来决定是否继续执行。 - 固定次数循环(如
for
):根据预设的迭代次数或元素列表来执行。 - 嵌套循环:将循环结构嵌套在另一循环内部,实现多层重复操作。
形象比喻:可以把循环想象成一个“自动售货机”——当用户持续投入硬币(满足条件)或选择商品(固定选项)时,售货机会重复执行“出货”动作,直到条件终止。
1.2 循环的三大核心要素
无论哪种循环类型,其逻辑都包含三个核心要素:
- 初始化:定义循环变量或条件的初始状态。
- 条件判断:每次循环前检查是否满足继续执行的条件。
- 迭代更新:在每次循环结束后,修改变量或状态以推进流程。
例如,在 for
循环中,初始化是定义起始值,条件判断是检查是否超过终止值,迭代更新是递增变量。
二、for 循环:固定范围的批量操作
2.1 基本语法与简单示例
for
循环是 shell 中最常用的循环结构,适用于已知迭代次数或已知元素列表的场景。其语法格式如下:
for 变量 in 列表
do
# 循环体:需要重复执行的命令
done
示例 1:遍历数字 1 到 3
for num in 1 2 3
do
echo "当前数字是:$num"
done
输出结果:
当前数字是:1
当前数字是:2
当前数字是:3
2.2 扩展用法:序列生成与文件遍历
2.2.1 序列生成(seq 命令)
当需要迭代大量连续数字时,手动输入列表显然不现实。此时可借助 seq
命令生成序列:
for i in $(seq 1 5)
do
echo "第 $i 次循环"
done
输出结果:
第 1 次循环
第 2 次循环
...(直到第5次)
2.2.2 遍历文件与目录
for
循环常用于批量处理文件。例如,遍历当前目录下的所有 .txt
文件:
for file in *.txt
do
echo "正在处理文件:$file"
# 可在此添加文件操作命令,如重命名、压缩等
done
2.3 嵌套 for 循环:二维操作的实现
当需要处理二维数据(如表格、坐标点)时,可以嵌套 for
循环:
for row in 1 2 3
do
for col in A B C
do
echo "单元格位置:$row$col"
done
done
输出结果:
单元格位置:1A
单元格位置:1B
...(直到 3C)
三、while 和 until 循环:动态条件的控制
3.1 while 循环:条件为真时持续执行
while
循环会持续执行代码块,直到条件变为“假”(False)。语法如下:
while [ 条件表达式 ]
do
# 循环体
done
示例:倒计时器
count=5
while [ $count -gt 0 ]
do
echo "倒计时:$count 秒"
sleep 1 # 暂停1秒
count=$((count - 1))
done
echo "时间到!"
3.2 until 循环:条件为假时才执行
until
循环与 while
相反,当条件为假时才执行循环体:
until [ $count -eq 0 ]
do
# 同样逻辑,但条件判断相反
done
注意:until
的使用场景较少,通常可以用 while
替代。
四、循环控制语句:跳出与跳过
4.1 break:立即终止循环
break
语句可强制退出当前循环。例如,在找到特定文件后停止遍历:
for file in *.log
do
if [ -f "$file" ] && grep -q "ERROR" "$file"; then
echo "发现错误文件:$file"
break
fi
done
4.2 continue:跳过当前迭代
continue
会跳过当前循环的剩余代码,并直接进入下一次迭代。例如,跳过偶数:
for num in {1..5}
do
if [ $((num % 2)) -eq 0 ]; then
continue
fi
echo "奇数:$num"
done
输出结果:
奇数:1
奇数:3
奇数:5
五、实际案例与高级技巧
5.1 案例 1:批量重命名文件
假设当前目录下有多个文件名以 old_
开头,需批量改为 new_
:
for file in old_*
do
new_file="new_${file#old_}"
mv "$file" "$new_file"
echo "已重命名:$file → $new_file"
done
5.2 案例 2:统计日志中的错误次数
通过 while
循环逐行读取日志文件,并统计包含 ERROR
的行数:
error_count=0
while read -r line; do
if [[ $line == *"ERROR"* ]]; then
((error_count++))
fi
done < error.log
echo "错误总数:$error_count"
5.3 高级技巧:循环性能优化
- 避免不必要的重复计算:例如,将
$(command)
的结果存储在变量中,而非每次循环都重新执行。 - 使用
continue
减少嵌套:通过提前跳过无效迭代,减少代码层级。
六、常见问题与注意事项
6.1 空列表的陷阱
当 for
循环的 in
列表为空时,循环体仍会执行一次,导致潜在错误。例如:
for file in *.jpg
do
echo "处理图片:$file" # 若无 .jpg 文件,$file 的值为 "/*.jpg"
done
解决方案:使用 nullglob
选项:
shopt -s nullglob
6.2 变量作用域与修改
在循环内部修改变量时,需确保其作用域正确。例如,i
在 for
循环结束后仍保留最终值:
for i in 1 2 3
do
echo "循环内:$i"
done
echo "循环外:$i" # 输出 3
结论
通过本文的学习,读者应已掌握 shell 循环 的核心语法、应用场景及优化技巧。无论是 for
的固定迭代、while
的动态控制,还是 break/continue
的流程调整,这些工具都能帮助开发者高效处理重复性任务。
建议读者通过实际编写脚本(如文件批量处理、日志分析)来巩固知识,并逐步尝试结合条件判断、函数等高级特性,构建更复杂的自动化流程。记住,实践是掌握循环逻辑的最佳途径!
(全文约 1600 字)