Shell for 循环
《Shell for 循环》深度学习版 🧠
🎉 欢迎来到 Shell 编程中极为关键的一章 —— for 循环。它是 Linux Shell 脚本中最常用的迭代结构,是实现“批量处理、重复操作”的核心工具。掌握它,你就能写出真正智能、自动化的脚本!
🎯 学习目标
- 理解
for循环的基本语法与执行流程 - 掌握传统
for in list和 C 风格for (( ))的写法 - 能在实际脚本中灵活使用通配符、命令替换、数组等迭代方式
- 学会结合
if判断、break、continue实现复杂逻辑控制 - 避免常见陷阱和语法错误,写出健壮可靠的 Shell 迭代语句
⭐ 核心重点(知识点速览)
| 类型 | 内容 | 描述 |
|---|---|---|
| 基本语法 | for var in list; do ... done |
最常用的传统循环结构 |
| C 风格语法 | for ((i=start; i<=end; i++)); do ... done |
更适合数值范围的循环 |
| 变量列表 | "item1" "item2" 或 $(ls) |
支持变量、命令输出、数组等 |
| 控制结构 | break, continue |
控制循环流程 |
| 通配符 | *.txt |
批量处理文件时非常实用 |
| 数组遍历 | ${arr[@]} |
结合数组实现更复杂的迭代 |
| 不同 shell 差异 | bash vs dash | 注意兼容性问题 |
📖 详细讲解
一、基本语法结构
✅ 传统 for 循环格式:
for var in item1 item2 item3 ...
do
# 循环体
done
✅ 示例:遍历字符串列表
for name in Alice Bob Charlie
do
echo "欢迎用户:$name"
done
输出:
欢迎用户:Alice
欢迎用户:Bob
欢迎用户:Charlie
二、C 风格 for 循环(Bash 特有)
适用于数字范围的循环,语法类似 C 语言。
for ((i=1; i<=5; i++))
do
echo "第 $i 次循环"
done
💡 该语法只能在 Bash 中使用,dash/sh 不支持。
三、使用通配符批量处理文件 📁
这是最常用于自动化任务的技巧之一。
✅ 示例:批量重命名 .log 文件为 .bak
for file in *.log
do
mv "$file" "${file%.log}.bak"
done
💡 解释:
*.log匹配当前目录下所有.log文件${file%.log}表示去掉文件名后缀.log
四、结合命令替换进行动态迭代 🔍
你可以将命令的结果作为循环的输入。
✅ 示例:列出所有正在运行的服务名称
for service in $(systemctl list-units --type=service --state=running | grep -v 'Loaded' | awk '{print $1}')
do
echo "服务正在运行:$service"
done
五、结合数组进行高级迭代 🧱
数组非常适合存储多个元素并逐个处理。
✅ 示例:定义数组并遍历
users=("Alice" "Bob" "Charlie")
for user in "${users[@]}"
do
echo "用户:$user"
done
六、嵌套循环与控制结构 🔄
你可以在一个循环内部再嵌套另一个循环,也可以使用 break 和 continue 控制流程。
✅ 示例:打印乘法表(9x9)
for i in {1..9}
do
for j in $(seq 1 $i)
do
echo -n "$j*$i=$((i*j)) "
done
echo ""
done
✅ 示例:跳过特定值
for num in {1..10}
do
if [ $num -eq 5 ]; then
continue # 跳过数字 5
fi
echo "数字:$num"
done
七、实战案例分析 🧪
🎯 场景一:批量创建用户 + 设置密码
users=("alice" "bob" "charlie")
for user in "${users[@]}"
do
if id "$user" &>/dev/null; then
echo "⚠️ 用户 $user 已存在"
else
useradd "$user"
echo "password123" | passwd "$user" --stdin &>/dev/null
echo "✅ 用户 $user 已创建"
fi
done
🎯 场景二:清理临时文件 + 输出日志
log_file="/var/log/cleaner.log"
timestamp=$(date "+%Y-%m-%d %T")
echo "[$timestamp] 开始清理 /tmp 下的 .tmp 文件..." >> "$log_file"
count=0
for file in /tmp/*.tmp
do
rm -f "$file"
count=$((count + 1))
done
echo "[$timestamp] 共删除 $count 个临时文件" >> "$log_file"
🎯 场景三:检查服务器状态 + 发送通知
servers=("web01" "db01" "cache01")
for server in "${servers[@]}"
do
ping -c 1 "$server" &>/dev/null
if [ $? -eq 0 ]; then
echo "🟢 服务器 $server 正常"
else
echo "🔴 服务器 $server 不可达!"
# 可以在此加入发送邮件或报警逻辑
fi
done
八、不同系统的差异与注意事项 ⚠️
| 项目 | Bash | Dash (Ubuntu 默认) | zsh |
|---|---|---|---|
支持 (( )) |
✅ | ❌ | ✅ |
| 支持数组 | ✅ | ✅(部分) | ✅ |
支持 continue / break |
✅ | ✅ | ✅ |
| 推荐脚本开头 | #!/bin/bash |
#!/bin/sh |
#!/bin/zsh |
| 推荐写法 | 使用 for in |
使用 POSIX 兼容写法 | 使用高级特性 |
📝 小贴士:
- 在 Ubuntu 系统中,默认
/bin/sh是dash,不支持(( )),所以如果你要使用高级特性,请确保脚本开头为#!/bin/bash。 - 使用双引号包裹变量,防止路径含空格出错。
- 多层循环建议用缩进保持可读性。
⚠️ 常见陷阱 & 解决方案
| 问题 | 原因 | 解决方法 |
|---|---|---|
command not found |
使用了 dash 不支持的语法 | 改为 #!/bin/bash |
unexpected token |
语法错误,如缺少 do 或 done |
检查括号和关键字是否正确 |
| 无法匹配文件 | 通配符未加引号导致展开失败 | 使用双引号或测试是否存在文件 |
| 变量未更新 | 在子 shell 中修改变量 | 使用全局变量或函数封装 |
| 循环未执行 | 列表为空 | 加入判断或调试输出 |
🧠 总结与小贴士
| 技巧 | 说明 |
|---|---|
for 是 Shell 的“发动机” |
让脚本能批量执行任务 |
推荐使用 for in list |
兼容性最好 |
使用 (( )) 更适合数值范围 |
Bash 特有功能 |
| 始终对变量加双引号 | 防止空格或未定义变量出错 |
结合 if 构建复杂逻辑 |
让脚本具备“判断能力” |
| 善用通配符和数组 | 提升灵活性 |
| 避免直接在循环中频繁调用外部命令 | 影响性能,应尽量合并处理 |
📚 推荐练习题(可选)
- 编写一个脚本,遍历
/etc/passwd中的所有用户,并输出 UID 和用户名。 - 写一个脚本,遍历指定目录下的所有
.txt文件,并统计每个文件的行数。 - 实现一个脚本,生成从 1 到 100 的奇数列表。
- 编写一个脚本,检查系统中所有用户是否都有家目录。
- 创建一个备份脚本,自动压缩并归档
/var/log/目录中的.log文件。
🎯 下一章预告:《Shell while/until 循环》
你已经掌握了如何进行批量处理和迭代操作,下一步我们将学习如何根据条件来决定是否继续循环 —— 使用 while 和 until,让你的脚本真正“动起来”,并且能响应实时变化的数据!
需要我继续为你生成下一章内容吗?😊

浙公网安备 33010602011771号