shell for 循环 数组(完整教程)

Shell for 循环 数组:从入门到实战应用

在日常的 Linux 系统运维、自动化脚本编写中,shell 脚本是不可或缺的工具。而其中,for 循环与数组的结合,正是实现批量处理任务的核心利器。如果你正在学习 shell 编程,那么掌握 shell for 循环 数组 的用法,就如同掌握了打开自动化大门的钥匙。

想象一下:你有一批日志文件需要压缩,或者要批量创建用户账号,又或者要检查多个服务是否运行。手动一条条执行?效率太低。而通过 shell for 循环遍历数组,一次写代码,就能自动完成几十甚至上百次重复操作。这就是脚本真正的价值所在。

本文将带你从零开始,一步步掌握 shell 中 for 循环与数组的搭配使用,结合真实案例,让你不仅“会用”,还能“用得好”。


创建数组与初始化

在 shell 中,数组是一种可以存储多个值的数据结构。它就像一个“收纳盒”,每个格子可以放一个数据。我们可以通过以下方式创建数组:

fruits=("苹果" "香蕉" "橙子" "葡萄")

colors[0]="红色"
colors[1]="绿色"
colors[2]="蓝色"

注意:数组的索引从 0 开始,和大多数编程语言一致。比如 colors[0] 指向“红色”。

在实际使用中,我们常常会结合 read 命令从用户输入中读取数组内容,或者从文件中读取数据构建数组。例如:

echo "请输入三个城市名,每行一个:"
read -r city1
read -r city2
read -r city3

cities=("$city1" "$city2" "$city3")

✅ 小贴士:使用双引号 "$var" 包裹变量,可以避免空格导致的分割问题,尤其在路径或包含空格的字符串中非常关键。


基础 for 循环语法与数组遍历

最基础的 for 循环语法是:

for variable in list; do
    # 执行命令
done

list 是一个数组时,循环会逐个取出数组中的元素,赋值给 variable。来看一个完整示例:

fruits=("苹果" "香蕉" "橙子" "葡萄")

for fruit in "${fruits[@]}"; do
    echo "今天吃一个 ${fruit}。"
done

输出结果:

今天吃一个 苹果。
今天吃一个 香蕉。
今天吃一个 橙子。
今天吃一个 葡萄。

📌 关键点说明

  • fruits[@] 表示“数组所有元素”,必须加双引号 ",否则在元素含空格时会出错。
  • fruits[*] 也表示所有元素,但会合并成一个字符串,通常用于需要整体处理的情况。
  • 若不加引号,比如写成 for fruit in ${fruits[@]},当数组中有“西瓜”这种带空格的元素时,会被当作两个元素处理,导致错误。

✅ 这就像你把一串珠子排好,"${fruits[@]}" 是一个一个拿珠子,而 "$fruits[*]" 是把整串珠子拿下来,可能打结,所以要小心使用。


遍历数组索引与值并行处理

有时我们不仅需要知道元素内容,还需要知道它的位置(索引)。这时可以使用 for 循环配合 lengthseq 命令:

students=("小明" "小红" "小刚" "小丽")

length=${#students[@]}

for i in $(seq 0 $((length - 1))); do
    echo "第 $((i + 1)) 位同学是:${students[i]}"
done

输出:

第 1 位同学是:小明
第 2 位同学是:小红
第 3 位同学是:小刚
第 4 位同学是:小丽

💡 这种方式特别适合需要对元素进行编号、排序或条件判断的场景,比如批量重命名文件时,需要按顺序加编号。


实战案例:批量创建用户账号

假设你需要为新入职的 5 名员工创建系统账号,名字分别为 zhangsanlisiwangwuzhaoliusunqi。手动执行 useradd 命令太麻烦,可以用脚本自动完成:

users=("zhangsan" "lisi" "wangwu" "zhaoliu" "sunqi")

for user in "${users[@]}"; do
    # 检查用户是否已存在
    if id "$user" &>/dev/null; then
        echo "用户 $user 已存在,跳过。"
    else
        # 创建用户并设置默认密码(可选)
        useradd -m -s /bin/bash "$user"
        echo "用户 $user 创建成功。"
    fi
done

📌 注释说明

  • id "$user" &>/dev/null:检查用户是否存在,&>/dev/null 表示将标准输出和错误输出都丢弃,不打印。
  • -m:创建用户的主目录。
  • -s /bin/bash:设置默认 shell 为 bash。
  • "$user":使用双引号防止用户名含特殊字符(如 user@123)出错。

这个脚本可直接保存为 .sh 文件,通过 bash script.sh 执行,瞬间完成批量操作。


多维数组模拟与复杂数据处理

Shell 本身不支持真正的多维数组,但可以通过“字符串拼接”或“嵌套数组”方式模拟。例如,我们要处理一组“学生-成绩”数据:

students_scores=("小明 95" "小红 87" "小刚 92" "小丽 88")

for entry in "${students_scores[@]}"; do
    # 使用 read 命令拆分字符串
    read name score <<< "$entry"
    
    # 判断成绩等级
    if [ "$score" -ge 90 ]; then
        grade="优秀"
    elif [ "$score" -ge 80 ]; then
        grade="良好"
    elif [ "$score" -ge 60 ]; then
        grade="及格"
    else
        grade="不及格"
    fi

    echo "${name} 的成绩是 ${score},等级为:${grade}"
done

输出:

小明 的成绩是 95,等级为:优秀
小红 的成绩是 87,等级为:良好
小刚 的成绩是 92,等级为:优秀
小丽 的成绩是 88,等级为:良好

✅ 这种方式虽然不是“真正的多维数组”,但在实际脚本中非常实用,尤其适合处理配置、日志、表格数据。


常见陷阱与最佳实践

在使用 shell for 循环 数组 时,有几个常见错误必须避开:

陷阱 正确做法 原因说明
不加引号:for i in ${arr[@]} 使用 for i in "${arr[@]}" 防止含空格的元素被拆分
数组索引从 1 开始 索引从 0 开始 脚本逻辑错误,导致越界
忘记 [@][*] 使用 [@] 获取所有元素 [*] 会合并为字符串,可能出错
使用 seq 时未处理边界 加上 ((length - 1)) 避免索引越界

✅ 推荐:在脚本开头加上 set -euo pipefail,开启严格模式,能提前发现很多潜在错误。


总结与建议

通过本文的学习,你已经掌握了 shell for 循环 数组 的核心用法:从创建、遍历、索引使用,到实战案例和常见陷阱规避。这些技能不仅能提升你的脚本编写效率,还能让你在运维、自动化、CI/CD 等场景中游刃有余。

记住:shell 脚本不是“一次性工具”,而是“可复用、可维护”的工程代码。写得清晰、注释完整、处理边界,才能真正发挥它的威力。

最后,不妨动手试试:写一个脚本,自动备份指定目录下的所有 .log 文件,并按日期命名。用数组存储文件列表,再用 for 循环完成压缩和移动。你会发现,原来自动化并不难,只要掌握好 shell for 循环 数组 的组合拳。

编程之路,始于一个个小脚本。愿你每一次运行脚本,都能收获一份高效与成就感。