Linux Shell 循环控制:从基础到实战,掌握重复执行的核心技巧


本文收录于《 Linux Shell 学习从入门到精通

Linux Shell 循环控制:从基础到实战,掌握重复执行的核心技巧

在 Linux 系统管理和脚本开发中,重复执行某段代码是高频需求。Shell 提供的循环控制功能,能让脚本脱离“重复写代码”的低效模式,实现自动化批量操作。无论是处理批量文件、遍历目录内容,还是按条件重复任务,掌握循环控制都是提升 Shell 脚本能力的关键。

一、Shell 循环的核心类型:for、while、until

Shell 支持三种主流循环结构,每种结构适用场景不同,需根据“是否明确循环次数”“循环终止条件”来选择。

1. for 循环:明确次数的“遍历型”循环

for 循环适合已知循环次数遍历固定列表的场景,比如处理指定文件、遍历数组元素等。

基础语法(列表遍历)
for 变量名 in 列表
do
    循环体(需要重复执行的命令)
done
实战案例:批量重命名文件

将当前目录下所有 .txt 文件重命名为 old_原文件名.txt

# 遍历当前目录下所有 .txt 文件
for file in *.txt
do
    # 重命名文件,$file 代表当前遍历到的文件名
    mv "$file" "old_$file"
done
进阶用法:数字范围遍历

无需手动写列表,用 {起始..结束}seq 命令 生成数字序列:

# 方式1:用 { } 生成 1-5 的数字
for i in {1..5}
do
    echo "当前数字:$i"
done

# 方式2:用 seq 生成 2-10 的偶数(步长为2)
for j in $(seq 2 2 10)
do
    echo "当前偶数:$j"
done

2. while 循环:“条件满足就执行”的循环

while 循环适合未知循环次数、仅知道“循环终止条件”的场景,只要条件为“真”(返回值 0),就持续执行循环体。

基础语法
while 条件表达式
do
    循环体
done
实战案例:读取文件内容

逐行读取 userlist.txt 文件(每行是一个用户名),并输出欢迎信息:

# 用 cat 读取文件内容,通过管道传给 while 循环
cat userlist.txt | while read username
do
    echo "欢迎您,$username!"
done

# 更高效的写法(避免创建子进程)
while read username
do
    echo "欢迎您,$username!"
done < userlist.txt
注意:避免“死循环”

若条件表达式始终为“真”,会导致循环无限执行,需确保循环体内有“让条件最终为假”的逻辑。例如:

# 正确示例:计数器达到 5 时终止
i=1
while [ $i -le 5 ]
do
    echo "计数器:$i"
    i=$((i+1))  # 计数器自增,最终让条件不满足
done

3. until 循环:“条件不满足就执行”的循环

until 循环与 while 逻辑相反:只要条件为“假”(返回值非 0),就执行循环体,直到条件为“真”时终止。适合“直到某个条件达成才停止”的场景。

基础语法
until 条件表达式
do
    循环体
done
实战案例:等待服务启动

直到 8080 端口被占用(服务启动),才停止循环:

# 初始假设服务未启动(条件为假)
until nc -z localhost 8080
do
    echo "等待服务启动..."
    sleep 2  # 每隔 2 秒检查一次,避免频繁占用资源
done
echo "服务已启动!"

二、循环控制符:break、continue、exit

当循环执行到特定场景时,需要灵活调整流程(比如提前终止循环、跳过当前迭代),这就需要用到循环控制符。

1. break:终止当前循环

遇到 break 时,会直接跳出当前所在的循环,执行循环之后的代码。

案例:找到目标文件后停止遍历

/home 目录下查找 target.txt,找到后立即停止:

for file in $(find /home -name "target.txt")
do
    echo "找到目标文件:$file"
    break  # 找到后跳出循环,不再继续查找
done
echo "查找结束"

2. continue:跳过当前迭代,进入下一次

遇到 continue 时,会跳过当前迭代剩余的代码,直接进入下一次循环判断。

案例:处理文件时跳过空文件

遍历 .txt 文件,若文件大小为 0,则跳过,不执行后续处理:

for file in *.txt
do
    # 检查文件大小是否为 0
    if [ -s "$file" -eq 0 ]; then
        echo "跳过空文件:$file"
        continue  # 跳过当前文件,处理下一个
    fi
    # 非空文件的处理逻辑(例如统计行数)
    line_count=$(wc -l < "$file")
    echo "$file 的行数:$line_count"
done

3. exit:终止整个脚本

exit 会直接结束整个脚本的运行,无论当前处于哪个循环或代码块,常用于“遇到致命错误时停止脚本”。

案例:参数错误时终止脚本

脚本需要接收一个文件名作为参数,若未传入参数,则提示错误并终止:

# 检查参数数量是否为 1
if [ $# -ne 1 ]; then
    echo "错误:请传入一个文件名作为参数!"
    exit 1  # 退出脚本,返回状态码 1(表示错误)
fi

# 参数正确时的处理逻辑
file=$1
echo "正在处理文件:$file"

三、实战:综合循环案例

通过一个“批量备份日志文件”的案例,整合 for 循环、while 循环和控制符的用法:

需求:

  1. 备份 /var/log 目录下 7 天前的 .log 文件
  2. 备份文件存到 /backup/logs 目录,命名格式为“文件名_日期.tar.gz”
  3. 若备份目录不存在,先创建;若备份失败,提示错误并继续下一个文件
#!/bin/bash

# 1. 定义变量
BACKUP_DIR="/backup/logs"
DATE=$(date +%Y%m%d)  # 当前日期,格式:20240520

# 2. 检查备份目录,不存在则创建
if [ ! -d "$BACKUP_DIR" ]; then
    mkdir -p "$BACKUP_DIR"
    echo "创建备份目录:$BACKUP_DIR"
fi

# 3. 遍历 7 天前的 .log 文件(用 find 命令筛选)
for log_file in $(find /var/log -name "*.log" -mtime +7)
do
    # 提取文件名(去掉路径)
    filename=$(basename "$log_file")
    # 定义备份文件名
    backup_file="$BACKUP_DIR/${filename}_${DATE}.tar.gz"

    # 4. 执行备份(打包压缩)
    echo "正在备份:$log_file"
    tar -zcf "$backup_file" "$log_file"

    # 5. 检查备份是否成功($? 是上一条命令的返回状态码,0 为成功)
    if [ $? -ne 0 ]; then
        echo "错误:$log_file 备份失败!"
        continue  # 备份失败,跳过删除原文件,处理下一个
    fi

    # 6. 备份成功后,删除原文件(可选)
    rm -f "$log_file"
    echo "$log_file 备份完成,已删除原文件"
done

echo "所有符合条件的日志文件备份处理完毕"

总结

Shell 循环控制是脚本自动化的核心,关键在于“选对循环类型”和“用好控制符”:

  • 明确循环次数或遍历列表 → 用 for 循环
  • 条件满足时执行 → 用 while 循环
  • 条件不满足时执行 → 用 until 循环
  • 终止循环 → break;跳过当前迭代 → continue;终止脚本 → exit

若有转载,请标明出处:https://blog.youkuaiyun.com/CharlesYuangc/article/details/153472710

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

君九@DBA

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值