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 循环配合 length 和 seq 命令:
students=("小明" "小红" "小刚" "小丽")
length=${#students[@]}
for i in $(seq 0 $((length - 1))); do
echo "第 $((i + 1)) 位同学是:${students[i]}"
done
输出:
第 1 位同学是:小明
第 2 位同学是:小红
第 3 位同学是:小刚
第 4 位同学是:小丽
💡 这种方式特别适合需要对元素进行编号、排序或条件判断的场景,比如批量重命名文件时,需要按顺序加编号。
实战案例:批量创建用户账号
假设你需要为新入职的 5 名员工创建系统账号,名字分别为 zhangsan、lisi、wangwu、zhaoliu、sunqi。手动执行 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 循环 数组 的组合拳。
编程之路,始于一个个小脚本。愿你每一次运行脚本,都能收获一份高效与成就感。