批量任务被中断的痛,谁经历过谁知道
跑了一上午的Shell脚本,处理了80%的数据,突然SSH断了、服务器重启了、或者你不小心按了Ctrl+C——一切归零,从头再来。这种体验,干过运维的都懂。
批量任务时间越长,中断的代价就越大。几百个文件要处理、几万条数据要迁移、上千个URL要检测,一旦中断重跑,浪费的不仅是时间,还有你的耐心。
解决这个问题的核心思路就一个词:断点续传。让脚本在执行过程中把进度记下来,下次启动时自动跳过已处理的部分,从断点接着跑。
这篇文章不讲虚的,直接上3个实战方案,从简单到进阶,覆盖大部分Shell批量任务的场景。
方案一:文件标记法——最简单的断点续传
思路:每成功处理一个任务,就在一个标记文件里记一笔。重启时先读标记文件,跳过已完成的任务。
实现步骤
- 创建一个进度文件,比如 progress.log,用来记录已成功处理的任务ID或文件名
- 循环处理前先检查该任务是否已在进度文件中
- 处理成功后,把任务标识追加到进度文件
- 脚本重启后,先加载进度文件到内存,跳过已完成的条目
完整代码示例
#!/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辅助作者原创,未经许可,转载请保留原文链接。

发表评论