shell for循环(千字长文)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 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+ 小伙伴加入学习 ,欢迎点击围观

从日常场景理解For循环

想象你正在一家快递分拣中心工作,传送带上不断有包裹经过。你的任务是逐个检查包裹的条形码,并根据目的地将它们分类到不同的区域。这个过程就是典型的“重复执行固定操作”的场景——而Shell For循环正是用来解决这类问题的利器。它允许我们通过简洁的语法,让计算机代替人类完成重复性任务,例如批量处理文件、遍历服务器列表执行命令等。

Shell For循环的基础语法与执行机制

核心语法结构

Shell中的For循环基本语法遵循以下模板:

for 变量 in 列表  
do  
    # 需要重复执行的代码块  
    命令1  
    命令2  
    ...  
done  

这里的列表可以是直接指定的值序列(如1 2 3)、通过通配符匹配的文件名(如*.txt),或是通过命令生成的动态数据流。每个循环迭代时,变量都会被赋予列表中的下一个元素值。

简单示例演示

以下代码将遍历数字1到3并输出:

for number in 1 2 3  
do  
    echo "当前数字是:$number"  
done  

执行结果:

当前数字是:1  
当前数字是:2  
当前数字是:3  

列表生成的多样化

实际应用中,列表来源可灵活扩展:

  • 静态列表:直接输入值,如in red green blue
  • 通配符匹配in *.log将匹配当前目录下所有.log文件
  • 命令输出:通过$(command)获取动态数据,例如in $(seq 5)生成1到5的数字序列

Shell For循环的四大核心应用场景

场景一:文件批量处理

假设需要将当前目录下所有.txt文件重命名为小写形式,可以这样实现:

for file in *.txt  
do  
    new_name=$(echo "$file" | tr '[:upper:]' '[:lower:]')  
    mv "$file" "$new_name"  
done  

这里tr命令负责转换大小写,mv执行重命名操作。注意双引号的使用可避免文件名含空格时的错误。

场景二:系统监控与日志分析

监控服务器CPU使用率的示例脚本:

for ((i=1; i<=5; i++))  
do  
    echo "第$i次检测:$(date)"  
    top -bn1 | grep "Cpu(s)"  
    sleep 5  
done  

这里使用了C风格的For循环语法for ((...)),配合sleep实现间隔检测。

场景三:自动化部署与配置

在虚拟化环境中批量创建用户账户:

users="dev1 dev2 dev3"  
for user in $users  
do  
    sudo useradd $user  
    echo "创建用户:$user"  
done  

此脚本通过预定义用户列表实现批量账号创建,特别适合系统初始化场景。

场景四:数据处理与转换

将CSV文件中的第三列数据提取并写入新文件:

input="data.csv"  
output="column3.txt"  
while IFS=, read -r col1 col2 col3  
do  
    echo "$col3" >> "$output"  
done < "$input"  

这里虽然使用while循环,但通过IFS字段分隔符设置,展示了处理结构化数据的典型模式。

进阶技巧:让循环更智能

技巧1:嵌套循环处理二维数据

for dir in /path/to/dirs/*  
do  
    for file in "$dir"/*  
    do  
        echo "目录:${dir##*/} 文件:${file##*/}"  
    done  
done  

通过双层循环遍历多级目录结构,${variable##pattern}语法可提取路径中的文件名部分。

技巧2:条件判断与循环结合

for file in *.jpg  
do  
    if [[ -f $file ]]; then  
        echo "处理图片:$file"  
        convert "$file" "processed_$file"  
    else  
        echo "跳过非文件项:$file"  
    fi  
done  

通过-f测试确保只处理真实文件,避免目录或符号链接的干扰。

技巧3:循环变量作用域管理

在循环体内修改全局变量需特别注意:

count=0  
for item in a b c  
do  
    ((count++))  
    echo "第$count项:$item"  
done  
echo "总项数:$count"  # 输出3  

此示例展示了变量在循环内外的一致性,但需避免在子shell中修改变量。

常见问题与解决方案

问题1:文件名包含空格导致错误

解决方案:

for file in *  
do  
    [[ -f "$file" ]] && echo "处理文件:$file"  
done  

双引号确保文件名完整传递,避免被拆分为多个参数。

问题2:循环效率低下

优化策略:

find . -type f -name "*.log" -exec echo "处理日志:{}" \;  

使用find-exec选项替代显式循环,减少子进程创建开销。

问题3:无限循环意外发生

安全防护:

MAX=100  
counter=0  
for (( ; ; ))  
do  
    ((counter++))  
    if [[ $counter -ge $MAX ]]; then break; fi  
    # 其他操作  
done  

设置最大循环次数作为安全阀,避免意外死循环。

实战案例:构建自动化备份脚本

#!/bin/bash  

BACKUP_DIR="/mnt/backup"  
LOG_FILE="/var/log/backup.log"  

for target in /home /etc /var/www  
do  
    timestamp=$(date +%Y%m%d%H%M)  
    tar -czf "$BACKUP_DIR/${target##*/}_$timestamp.tar.gz" "$target"  
    echo "[$(date)] 备份 $target 到 $BACKUP_DIR 成功" >> "$LOG_FILE"  
done  

find "$BACKUP_DIR" -type f -mtime +7 -exec rm {} \;  
echo "清理7天前备份完成" >> "$LOG_FILE"  

此脚本实现:

  1. 多目录增量备份
  2. 自动命名包含时间戳的压缩包
  3. 清理过期备份文件
  4. 日志记录功能

总结与进阶方向

通过本文,我们系统掌握了Shell For循环从基础语法到实战应用的完整知识体系。这个看似简单的结构,实则是构建复杂自动化流程的核心组件。建议读者从以下方向继续深入:

  • 学习whileuntil等其他循环结构
  • 掌握break/continue的精确控制
  • 结合read命令处理动态输入流
  • 运用set -x等调试技巧优化脚本

自动化是提升生产力的关键,而Shell For循环正是实现这一目标的基石。通过持续练习和实际项目应用,你将能编写出更高效、健壮的脚本解决方案。记住,每个复杂的系统,都是由无数个简单的循环结构组合而成的。

最新发布