简介
有用的备份不只是执行归档命令。你需要知道归档中包含哪些内容,确认它可以读取,恢复所需的文件,并确保无人值守运行时能够查看其状态。
在本实验中,你将根据清单备份一个小型应用工作区,恢复指定的单个文件,将整个流程转换为带时间戳的脚本,并安装 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 | 分钟 | 0–59 |
| 2 | 小时 | 0–23 |
| 3 | 月中的第几天 | 1–31 |
| 4 | 月份 | 1–12 |
| 5 | 星期几 | 0–7,星期日为 0 或 7 |
星号 * 表示所有允许的值。字段中的步长(例如 */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
输出应包含该注释,以及紧随其后的每 5 分钟执行一次的条目。检查已安装的结果,可以在依赖此计划之前发现编辑器中的错误。
测试日志并理解百分号转义
在此步骤中,你将测试备份日志,并了解 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 命令中时必须转义百分号的原因。



