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+ 小伙伴加入学习 ,欢迎点击围观

在 Shell 脚本编程中,for 循环数组是两个核心工具。它们的结合不仅能够高效处理批量数据,还能显著提升自动化脚本的灵活性。无论是遍历文件列表、处理日志数据,还是执行复杂操作,shell for 循环数组的组合都能帮助开发者快速实现目标。本文将从基础概念入手,结合实例逐步讲解如何掌握这一技能,并深入探讨其在实际场景中的应用。


一、Shell 数组:数据存储的“购物车”

1.1 数组是什么?

数组可以理解为一个“购物车”,能够一次性存放多个数据项。例如,存储多个文件名、用户列表或数字序列。在 Shell 中,数组的定义和操作相对简单,但需要注意其特性与语法细节。

1.1.1 数组的定义方式

Shell 数组支持多种定义方法,以下是常见的两种:

fruits=("apple" "banana" "cherry")  

vegetables[0]="carrot"  
vegetables[1]="broccoli"  
vegetables[2]="spinach"  

注意:在 Shell 中,数组索引默认从 0 开始,且无需预先声明数组长度。

1.1.2 访问数组元素

通过索引访问数组元素:

echo ${fruits[0]}  # 输出 "apple"  
echo ${vegetables[2]}  # 输出 "spinach"  

若需获取数组所有元素,使用 @*

echo ${fruits[@]}  # 输出 "apple banana cherry"(以空格分隔)  

1.1.3 数组长度

通过 $# 符号获取数组长度:

echo ${#fruits[@]}  # 输出 "3"  

二、For 循环:逐个处理数据的“传送带”

2.1 For 循环的语法结构

For 循环是 Shell 中最常用的迭代结构,语法如下:

for variable in item1 item2 item3 ...  
do  
    # 循环体  
done  

例如,遍历数字序列 1 2 3 4 5

for num in 1 2 3 4 5  
do  
    echo "当前数字是 $num"  
done  

2.2 使用序列生成器简化代码

Shell 支持通过 {start..end} 生成数字序列:

for num in {1..5}  
do  
    echo "当前数字是 $num"  
done  

甚至可以指定步长:

for num in {10..1..2}  
do  
    echo $num  # 输出 10 8 6 4 2  
done  

三、数组与 For 循环的结合:批量处理的“组合拳”

3.1 基础用法:遍历数组元素

通过 for 循环与数组结合,可以逐个处理数组中的元素。例如,打印所有水果名称:

fruits=("apple" "banana" "cherry")  
for fruit in "${fruits[@]}"  
do  
    echo "水果名称:$fruit"  
done  

关键点:使用双引号包裹 ${fruits[@]},避免因元素包含空格导致误拆分。

3.2 索引遍历:通过位置访问元素

若需同时获取元素索引和值,可通过 seqfor 循环结合索引实现:

for index in ${!fruits[@]}  
do  
    echo "索引 $index 对应的水果是:${fruits[$index]}"  
done  

输出结果:

索引 0 对应的水果是:apple  
索引 1 对应的水果是:banana  
索引 2 对应的水果是:cherry  

3.3 实际案例:批量处理文件

假设需要遍历当前目录下的所有 .txt 文件并统计行数:

files=(*.txt)  

for file in "${files[@]}"  
do  
    line_count=$(wc -l < "$file")  
    echo "$file 包含 $line_count 行"  
done  

四、进阶技巧:让循环更灵活的“工具箱”

4.1 多维数组:嵌套结构的处理

Shell 不直接支持多维数组,但可通过字符串分割模拟:

matrix="1,2,3;4,5,6;7,8,9"  

for row in ${matrix//;/ }  
do  
    # 遍历列  
    for num in ${row//,/ }  
    do  
        echo -n "$num "  
    done  
    echo ""  
done  

输出结果:

1 2 3  
4 5 6  
7 8 9  

4.2 嵌套循环:组合逻辑的“齿轮联动”

嵌套循环适用于需要双重遍历的场景,例如生成坐标点:

for x in {1..2}  
do  
    for y in {A..B}  
    do  
        echo "坐标 ($x, $y)"  
    done  
done  

输出结果:

坐标 (1, A)  
坐标 (1, B)  
坐标 (2, A)  
坐标 (2, B)  

4.3 变量引用与安全性

在循环中处理动态数据时,需注意变量引用的安全性。例如,处理包含空格的文件名:

files=("file 1.txt" "file2.txt")  

for file in ${files[@]}  
do  
    echo "文件名:$file"  
done  

for file in "${files[@]}"  
do  
    echo "文件名:$file"  
done  

五、常见问题与解决方案

5.1 数组索引越界

尝试访问超出范围的索引时,Shell 默认返回空值。可通过判断长度避免错误:

if [ $index -lt ${#fruits[@]} ]  
then  
    echo "元素存在:${fruits[$index]}"  
else  
    echo "索引越界"  
fi  

5.2 动态修改数组

在循环中动态添加或删除元素可能导致意外结果。建议在循环外操作数组:

for item in "${array[@]}"  
do  
    array+=("new_item")  
    ...  
done  

六、实战案例:日志分析脚本

6.1 需求:统计访问日志中的 IP 地址

假设日志文件 access.log 内容如下:

192.168.1.10 - [10/May/2023] "GET /home"  
192.168.1.11 - [10/May/2023] "POST /login"  
192.168.1.10 - [10/May/2023] "GET /about"  

编写脚本统计每个 IP 的访问次数:

declare -A ip_counts  # 声明关联数组  

while read -r line  
do  
    ip=$(echo $line | cut -d ' ' -f1)  
    ((ip_counts[$ip]++))  
done < access.log  

for ip in "${!ip_counts[@]}"  
do  
    echo "$ip 访问了 ${ip_counts[$ip]} 次"  
done  

输出结果:

192.168.1.10 访问了 2 次  
192.168.1.11 访问了 1 次  

七、结论

掌握 shell for 循环数组 的组合技巧,能够显著提升脚本的效率和可读性。从基础的数组定义到复杂的数据处理,通过实际案例的演练,开发者可以逐步构建出灵活且健壮的自动化解决方案。建议读者通过以下步骤深入学习:

  1. 从简单的数组遍历开始,逐步尝试嵌套循环和多维数据处理;
  2. 结合实际需求,例如文件管理、日志分析,设计具体脚本;
  3. 参考官方文档(如 man bash)了解高级特性,如关联数组、数组切片等。

通过持续实践,shell for 循环数组将成为你自动化工作流中的得力工具,帮助你轻松应对各类批量处理任务。

最新发布