shell for循环(建议收藏)

shell for循环:从零开始掌握自动化脚本的核心语法

在 Linux 系统中,shell 脚本是自动化任务的基石。无论是批量处理文件、监控日志,还是部署应用,shell for循环 都扮演着不可或缺的角色。对于初学者而言,它可能看起来像是一串神秘符号,但一旦掌握其原理,你会发现它就像一条自动流水线,能高效完成重复性工作。今天,我们就来拆解 shell for循环 的本质,带你一步步从“看不懂”变成“用得顺”。


什么是 shell for循环?

shell for循环 是一种控制结构,用于重复执行一组命令,直到满足特定条件为止。它的核心思想是“遍历”,就像你在超市里按货架顺序检查商品一样,for 就是那个“顺序检查”的流程控制器。

在 shell 中,for 循环最常见于处理一组固定值,比如文件名列表、数字序列或配置项。相比 while 循环(基于条件判断),for 更适合“我知道要处理多少项”的场景。


基础语法:最简单的 for 循环结构

我们先从最基础的语法开始,理解 shell for循环 的骨架结构。

for 变量名 in 值列表
do
    命令1
    命令2
    ...
done

关键点说明:

  • for:关键字,表示开始一个循环。
  • 变量名:在每次迭代中会自动赋值为列表中的一个元素。
  • in:连接变量和值列表。
  • do:标记循环体开始。
  • done:标记循环体结束。

💡 比喻:你可以把 for 循环想象成一个“快递分拣员”。他面前有一堆包裹(值列表),他每次拿起一个(变量赋值),贴上标签(执行命令),然后放回货架,直到所有包裹都处理完。

示例:打印数字列表

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

输出结果:

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

注释:

  • i 是循环变量,每次迭代会从列表中取一个值。
  • $i 表示变量 i 的值,必须用 $ 符号引用。
  • echo 是输出命令,用于查看当前值。
  • done 是必须的结束标记,缺少会导致语法错误。

用 for 循环处理文件列表

在实际工作中,shell for循环 最常见的用途之一就是批量处理文件。比如你有一堆日志文件,需要压缩归档。

示例:批量压缩日志文件

for file in access.log error.log debug.log
do
    # 使用 gzip 命令压缩每个文件
    gzip "$file"
    echo "已压缩文件: $file"
done

输出示例:

已压缩文件: access.log
已压缩文件: error.log
已压缩文件: debug.log

注意事项:

  • 文件名中如果包含空格或特殊字符,必须用双引号包裹变量,如 "$file",否则会出错。
  • gzip 会生成 access.log.gz 等新文件,原文件被删除。

✅ 小贴士:你也可以用通配符简化写法,比如 for file in *.log,这样就不用手动列出每个文件名。


使用 seq 命令生成数字序列

当你需要遍历连续的数字时,seq 命令是 shell for循环 的好搭档。它能生成指定范围的数字序列。

示例:从 1 到 10 打印数字

for num in $(seq 1 10)
do
    echo "第 $num 个数字"
done

输出:

第 1 个数字
第 2 个数字
...
第 10 个数字

注释:

  • $(seq 1 10) 是命令替换,执行 seq 1 10 并返回结果(1 到 10 的数字)。
  • 括号 $(...) 用于获取命令的输出作为 in 后的值列表。

高级用法:步长控制

for i in $(seq 2 2 20)
do
    echo "偶数: $i"
done

输出:

偶数: 2
偶数: 4
偶数: 6
...
偶数: 20

解释:

  • seq 2 2 20 表示从 2 开始,每次加 2,直到 20。
  • 这在需要跳着处理数据时非常有用,比如处理每隔 5 分钟的日志。

与数组配合使用:处理复杂数据结构

在 shell 脚本中,你可以定义数组来存储一组值,再用 for 循环遍历它们。

创建数组与初始化

projects=("Vue 3.0" "React 18" "Angular 14" "Svelte 5")

for project in "${projects[@]}"
do
    echo "正在部署项目: $project"
    # 模拟部署命令
    # git pull origin main
    # npm install
    # npm run build
done

输出:

正在部署项目: Vue 3.0
正在部署项目: React 18
正在部署项目: Angular 14
正在部署项目: Svelte 5

关键语法说明:

  • projects=("Vue 3.0" "React 18" ...):定义数组,元素用空格分隔。
  • "${projects[@]}":表示数组所有元素,必须加双引号,防止空格问题。
  • @ 是数组展开符号,表示“所有元素”。

⚠️ 注意:如果不用双引号,比如 ${projects[*]},当元素含空格时会出错。所以建议始终用 "${projects[@]}"


实用场景:批量创建用户账号

下面是一个真实项目中的典型应用:批量创建测试用户。

示例:创建 10 个用户

prefix="testuser"

for i in $(seq 1 10)
do
    username="${prefix}${i}"
    
    # 检查用户是否存在
    if id "$username" &>/dev/null
    then
        echo "用户 $username 已存在,跳过。"
    else
        # 创建用户并设置密码
        useradd -m "$username"
        echo "$username:password123" | chpasswd
        echo "成功创建用户: $username"
    fi
done

说明:

  • id "$username" &>/dev/null:检查用户是否存在,&>/dev/null 表示忽略输出。
  • useradd -m:创建用户并自动创建家目录。
  • chpasswd:批量设置密码,输入格式为 用户名:密码
  • &>/dev/null 是重定向,避免命令输出干扰脚本。

🛡️ 安全提示:实际生产中不应使用明文密码。此例仅用于演示,生产环境应使用密钥或 LDAP。


常见陷阱与最佳实践

1. 变量未加引号导致错误

for file in *.log
do
    echo "处理: $file"
done

如果文件名是 error log.txt(含空格),脚本会误认为是两个文件,导致错误。

✅ 正确做法:

for file in *.log
do
    echo "处理: $file"
done

2. 使用 $(seq) 时避免空值

如果 seq 生成空结果,循环不会执行。建议加判断:

numbers=$(seq 1 5)
if [ -z "$numbers" ]; then
    echo "没有生成数字"
else
    for num in $numbers
    do
        echo $num
    done
fi

总结:掌握 shell for循环 的核心价值

shell for循环 是自动化脚本的“发动机”,它让重复性任务变得简单、可靠。通过本文的学习,你已经掌握了:

  • 基础语法结构与执行流程;
  • 处理文件列表的实用技巧;
  • seq 命令结合生成数字序列;
  • 与数组协作处理复杂数据;
  • 实际项目中的真实应用案例。

更重要的是,你学会了如何避免常见陷阱,写出健壮的脚本。下次当你需要处理 100 个文件、部署 50 个服务、或生成 1000 行测试数据时,别再手动操作——让 shell for循环 为你代劳。

💬 记住:一个优秀的脚本,不是因为它写了多少行代码,而是因为它能用最少的代码完成最多的事。而 shell for循环,正是实现这一目标的利器。