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 脚本中,循环主要分为三类:

  • 条件循环(如 whileuntil):根据条件是否成立来决定是否继续执行。
  • 固定次数循环(如 for):根据预设的迭代次数或元素列表来执行。
  • 嵌套循环:将循环结构嵌套在另一循环内部,实现多层重复操作。

形象比喻:可以把循环想象成一个“自动售货机”——当用户持续投入硬币(满足条件)或选择商品(固定选项)时,售货机会重复执行“出货”动作,直到条件终止。

1.2 循环的三大核心要素

无论哪种循环类型,其逻辑都包含三个核心要素:

  1. 初始化:定义循环变量或条件的初始状态。
  2. 条件判断:每次循环前检查是否满足继续执行的条件。
  3. 迭代更新:在每次循环结束后,修改变量或状态以推进流程。

例如,在 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 变量作用域与修改

在循环内部修改变量时,需确保其作用域正确。例如,ifor 循环结束后仍保留最终值:

for i in 1 2 3  
do  
    echo "循环内:$i"  
done  
echo "循环外:$i"  # 输出 3  

结论

通过本文的学习,读者应已掌握 shell 循环 的核心语法、应用场景及优化技巧。无论是 for 的固定迭代、while 的动态控制,还是 break/continue 的流程调整,这些工具都能帮助开发者高效处理重复性任务。

建议读者通过实际编写脚本(如文件批量处理、日志分析)来巩固知识,并逐步尝试结合条件判断、函数等高级特性,构建更复杂的自动化流程。记住,实践是掌握循环逻辑的最佳途径!


(全文约 1600 字)

最新发布