0

Shell脚本进度保存断点续传方法:3个实战方案让批量任务不怕中断

2026.07.02 | youres | 77次围观

批量任务被中断的痛,谁经历过谁知道

跑了一上午的Shell脚本,处理了80%的数据,突然SSH断了、服务器重启了、或者你不小心按了Ctrl+C——一切归零,从头再来。这种体验,干过运维的都懂。

批量任务时间越长,中断的代价就越大。几百个文件要处理、几万条数据要迁移、上千个URL要检测,一旦中断重跑,浪费的不仅是时间,还有你的耐心。

解决这个问题的核心思路就一个词:断点续传。让脚本在执行过程中把进度记下来,下次启动时自动跳过已处理的部分,从断点接着跑。

这篇文章不讲虚的,直接上3个实战方案,从简单到进阶,覆盖大部分Shell批量任务的场景。

方案一:文件标记法——最简单的断点续传

思路:每成功处理一个任务,就在一个标记文件里记一笔。重启时先读标记文件,跳过已完成的任务。

实现步骤

  1. 创建一个进度文件,比如 progress.log,用来记录已成功处理的任务ID或文件名
  2. 循环处理前先检查该任务是否已在进度文件中
  3. 处理成功后,把任务标识追加到进度文件
  4. 脚本重启后,先加载进度文件到内存,跳过已完成的条目

完整代码示例

#!/bin/bash
PROGRESS_FILE="progress.log"
TASKS_FILE="tasks.txt"

declare -A DONE
if [[ -f "" ]]; then
    while IFS= read -r line; do
        DONE[""]=1
    done < ""
fi

while IFS= read -r task; do
    if [[ -n "" ]]; then
        echo "跳过已完成: "
        continue
    fi
    echo "正在处理: "
    if process_task ""; then
        echo "" >> ""
        echo "完成: "
    else
        echo "失败: " >> error.log
    fi
done < ""

优点是简单直接,缺点是任务量很大时每次检查都要遍历进度文件会变慢。建议每处理一批再批量写一次,而不是每条都追加。

方案二:行号追踪法——处理大文件的利器

如果任务列表有几万行,文件标记法检查进度就很慢了。行号追踪法的思路更干脆:记录当前处理到第几行。

实现方式

#!/bin/bash
TASKS_FILE="tasks.txt"
POS_FILE="position.txt"

START_LINE=1
if [[ -f "" ]]; then
    START_LINE=
fi

sed -n ",\" "" | while IFS= read -r line; do
    if process ""; then
        CURRENT=
        echo "" > ""
    fi
done

关键点是用 sed 直接跳转到断点位置开始处理,而不是逐行跳过。对于超大文件,这个方案的效率优势非常明显。

方案三:数据库状态法——适合复杂业务场景

前面两个方案用文件存进度,简单场景够用。但如果任务有多个处理阶段、需要记录详细结果,用SQLite数据库做进度管理更规范。

使用SQLite管理任务状态

#!/bin/bash
DB_FILE="batch.db"

init_db() {
    sqlite3 "" <<'EOF'
CREATE TABLE IF NOT EXISTS tasks (
    id INTEGER PRIMARY KEY,
    name TEXT NOT NULL,
    status TEXT DEFAULT 'pending',
    retries INTEGER DEFAULT 0,
    result TEXT,
    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
EOF
}

get_pending() {
    sqlite3 "" "SELECT id, name FROM tasks WHERE status='pending' ORDER BY id;"
}

update_status() {
    sqlite3 "" "UPDATE tasks SET status='', result='',
        updated_at=datetime('now') WHERE id=;"
}

while IFS='|' read -r id name; do
    echo "处理: [] "
    if do_work ""; then
        update_status "" "done" "success"
    else
        update_status "" "failed" "error"
    fi
done < <(get_pending)

SQLite方案的优势:支持多状态管理、支持重试次数统计、查询效率远高于文本文件。依赖 sqlite3 命令行,好在多数Linux发行版都预装了。

断点续传的4个注意事项

  • 写入时机:不要每次循环都写进度文件,建议每处理10-50条批量写一次,或用信号触发写入
  • 原子性:写进度文件时先写临时文件再 mv 重命名,避免脚本意外中断导致进度文件损坏
  • 幂等性:每个任务的处理逻辑要保证幂等,重复执行不产生副作用,这样才能放心重跑
  • 信号处理:用 trap 捕获 SIGINT/SIGTERM,退出前保存当前进度,让下次启动损失最小

结语:断点续传是Shell脚本的进阶必修课

三种方案从简到繁,覆盖了大部分场景。文件标记法适合任务数不多的场景,行号追踪法适合大文件批量处理,SQLite方案适合需要精细管理的复杂业务。

真正上生产环境的脚本,断点续传不是锦上添花,而是刚需。定时任务、CI/CD流水线、数据迁移脚本,没做断点续传就是在赌服务器不出问题。

下次写批量处理脚本的时候,花10分钟加上进度保存,省下的是未来不知道多少小时的重复劳动。

相关推荐

版权声明

本文仅代表个人观点。
本文系AI辅助作者原创,未经许可,转载请保留原文链接。

发表评论