定时备份与恢复

LinuxBeginner
立即练习

简介

一次实用的备份不只是执行归档命令。你需要了解归档包含哪些内容,确认它可以正常读取,能够恢复所需文件,并让无人值守的执行过程可被观察和追踪。

在本实验中,你将根据清单备份一个小型应用工作区,恢复指定的单个文件,将整个流程转换为带时间戳的脚本,并安装 Cron 计划。所有自动化路径都使用绝对路径,因此任务不会依赖交互式 Shell 的当前目录。

使用清单定义备份范围

在此步骤中,你将创建一个清单:它是一个纯文本路径列表,让备份范围清晰可见且便于审核。

进入工作区:

cd /home/labex/project/backup-lab

创建一个清单,其中包含相对于 data 目录的路径:

cat > backup-manifest.txt <<'EOF'
config/app.conf
documents/runbook.txt
EOF

为条目添加编号,便于查看:

nl -ba backup-manifest.txt

使用 while 循环确认清单中列出的每个源文件都存在。运行前,先了解其结构:

  • IFS= 防止 Shell 删除行首或行尾的空白字符;
  • read -r item 将一整行读取到 item 中,同时不对反斜杠做特殊处理;
  • do ... done 包含针对每一行重复执行的命令;
  • < backup-manifest.txt 将清单作为循环的输入;
  • test -f 检查对应路径是否为普通文件,只有检查成功时,&& 才会输出 ready
while IFS= read -r item; do
  test -f "data/$item" && echo "ready: $item"
done < backup-manifest.txt

未列入清单的 documents/scratch.txt 文件特意不纳入此次受管理的备份范围。

根据清单创建归档

在此步骤中,你将使用 tar -T 从清单中读取文件名。-C data 选项会让归档使用简短的相对路径。

tar -czf backups/manual-backup.tar.gz -C data -T backup-manifest.txt

各选项含义如下:

  • -c:创建归档;
  • -z:使用 gzip 压缩;
  • -f:使用后面的归档文件名;
  • -C data:以 data 作为相对路径的基准目录;
  • -T backup-manifest.txt:从清单中读取要加入归档的文件。

检查生成的文件:

ls -lh backups/manual-backup.tar.gz

将其时间戳和大小与源文件进行比较:

stat -c '%n size=%s modified=%y' backups/manual-backup.tar.gz data/config/app.conf data/documents/runbook.txt

在不解压的情况下验证归档

在此步骤中,你将先测试归档,再正式依赖它。首先测试 gzip 数据流:

gzip -t backups/manual-backup.tar.gz

没有任何输出表示压缩数据流通过了完整性检查。现在列出 tar 中的文件,但不要解压:

tar -tzf backups/manual-backup.tar.gz | tee archive-contents.txt

将保存的文件列表与清单进行比较:

diff -u backup-manifest.txt archive-contents.txt

命令不应显示任何差异。确认未受管理的临时文件不在归档中:

if tar -tzf backups/manual-backup.tar.gz | grep -qx 'documents/scratch.txt'; then
  echo "Unexpected scratch file found"
else
  echo "Archive scope is correct"
fi

恢复指定的单个文件

在此步骤中,你将只恢复一个指定文件,避免覆盖无关数据。先模拟配置文件被意外删除:

rm data/config/app.conf
test -e data/config/app.conf || echo "app.conf is missing"

config/app.conf 单独解压到恢复目录:

rm -rf restore/*
tar -xzf backups/manual-backup.tar.gz -C restore config/app.conf

查看恢复的文件,然后将其复制回工作目录:

cat restore/config/app.conf
cp restore/config/app.conf data/config/app.conf
cmp -s restore/config/app.conf data/config/app.conf && echo "Configuration restored"

整个过程中只解压了归档中指定的成员文件。

创建带时间戳的备份脚本

在此步骤中,你将创建一个带时间戳的备份脚本。Cron 启动任务时使用的是受限环境,因此无人值守脚本内部应使用绝对路径。

创建 backup.sh

cat > backup.sh <<'EOF'
#!/bin/bash

source_dir=/home/labex/project/backup-lab/data
manifest=/home/labex/project/backup-lab/backup-manifest.txt
backup_dir=/home/labex/project/backup-lab/backups
timestamp=$(date +%Y%m%d-%H%M%S)
archive="$backup_dir/backup-$timestamp.tar.gz"

mkdir -p "$backup_dir"

if [ ! -d "$source_dir" ] || [ ! -f "$manifest" ]; then
  echo "Backup source or manifest is missing" >&2
  exit 1
fi

/bin/tar -czf "$archive" -C "$source_dir" -T "$manifest" || exit 1
/bin/tar -tzf "$archive" > "$archive.contents" || exit 1

echo "Created $archive"
exit 0
EOF

为脚本添加可执行权限,并立即测试,而不是等待 Cron 执行:

chmod u+x backup.sh
./backup.sh | tee last-backup.txt
ls -1 backups

时间戳会为每次执行生成唯一的文件名。对应的 .contents 文件会准确记录归档中包含的内容。

安装并检查 Cron 计划

在此步骤中,你将安装并检查个人 Cron 计划。Crontab 条目由 5 个计划字段和后面的命令组成:

位置 字段 通常范围
1 分钟 059
2 小时 023
3 月中的第几天 131
4 月份 112
5 星期几 07,星期日为 07

星号 * 表示该字段允许的所有值。像 */5 这样的步长表示该字段每 5 个单位执行一次。

minute hour day-of-month month day-of-week command

例如,*/5 * * * * 表示每 5 分钟执行一次;0 2 * * * 表示每天凌晨 02:00 执行。

crontab -e 会在编辑器中打开个人 Crontab。一个可靠的流程是先准备并安装已知正确的条目,再进行一次小型交互式编辑。创建一个使用绝对路径并同时记录标准输出和标准错误的条目:

cat > backup.crontab <<'EOF'
*/5 * * * * /home/labex/project/backup-lab/backup.sh >> /home/labex/project/backup-lab/logs/backup.log 2>&1
EOF

查看并安装它:

cat backup.crontab
crontab backup.crontab

现在使用 Nano 打开已经安装的 Crontab:

EDITOR=nano crontab -e

在计划任务上一行添加以下注释:

## LabEx managed backup schedule

Ctrl+O,再按 Enter 保存。按 Ctrl+X 退出 Nano 并返回 shell。使用 crontab -l 确认 Cron 实际读取的内容,并保存该输出:

crontab -l | tee installed-crontab.txt

输出中应先出现注释,随后是每五分钟执行一次的条目。检查已安装的结果,可以在真正依赖该计划前发现编辑错误。

测试日志并理解百分号转义

在此步骤中,你将测试备份日志,并了解 Cron 对百分号的特殊处理。首先手动运行计划任务中的命令:

/home/labex/project/backup-lab/backup.sh >> /home/labex/project/backup-lab/logs/backup.log 2>&1
tail -n 5 logs/backup.log
find backups -maxdepth 1 -type f -name 'backup-*.tar.gz' -printf '%f\n' | sort

时间戳是在 backup.sh 内部生成的,因此普通的 % 字符在脚本中可以直接使用。不过,Cron 会对 Crontab 命令中的未转义 % 做特殊处理。如果直接在 Crontab 条目中使用 date,必须为每个百分号添加反斜杠进行转义。

保存一个正确转义的示例,供后续参考:

cat > cron-date-example.txt <<'EOF'
0 2 * * * /bin/echo "backup-$(/bin/date +\%Y\%m\%d-\%H\%M\%S)" >> /home/labex/project/backup-lab/logs/date-example.log 2>&1
EOF
cat cron-date-example.txt

当前安装的任务仍然使用更简单的脚本方式。它采用绝对路径,为每个归档添加时间戳,并留下可在无人值守执行后检查的日志。

总结

你使用清单定义了备份范围,借助 tar -T 创建了归档,在不解压的情况下完成了验证,并恢复了指定的单个文件。随后,你编写了使用绝对路径的带时间戳备份脚本,安装并检查了 Cron 计划,将无人值守执行的输出重定向到日志中,并了解了当 date 直接出现在 Crontab 命令中时为什么必须转义百分号。