写备份脚本时,除了变量与引号,还要处理输出目录嵌套、失败半成品和文件名碰撞。下面只演示普通文件目录的实验备份,不用于在线数据库一致性备份。
前提与最小脚本
依赖 Bash、GNU realpath、mktemp、tar,准备两个独立测试目录。备份目标不能是源目录或其子目录,否则可能把归档自身打包进去。
#!/usr/bin/env bash
set -euo pipefail
umask 077
[[ $# -eq 2 ]] || { echo '用法:backup.sh 源目录 目标目录' >&2; exit 2; }
[[ -d "$1" ]] || { echo '源目录不存在' >&2; exit 1; }
source_dir=$(realpath -e -- "$1")
mkdir -p -- "$2"
backup_dir=$(realpath -e -- "$2")
if [[ "$source_dir" == / || "$backup_dir" == "$source_dir" || "$backup_dir" == "$source_dir/"* ]]; then
echo '请使用独立的源目录和备份目录;不允许备份根目录' >&2
exit 1
fi
tmp=$(mktemp "$backup_dir/backup-$(date +%Y%m%d-%H%M%S)-XXXXXX.partial")
trap 'rm -f -- "$tmp"' EXIT
tar -czf "$tmp" -C "$source_dir" .
gzip -t "$tmp"
tar -tzf "$tmp" >/dev/null
archive="${tmp%.partial}.tar.gz"
[[ ! -e "$archive" ]] || { echo '目标已存在' >&2; exit 1; }
mv -- "$tmp" "$archive"
printf '已生成:%s\n' "$archive"mktemp 为本次运行生成独立临时文件;成功校验后才改为正式名称。trap 只清理该临时文件,不递归删除目录。此示例没有并发锁与保留策略,不能直接代替本站正式备份。
一轮可复现实验
先在 ~/linux-lab/source 放两个文本文件,目标选 ~/linux-lab/backup。运行 bash -n backup.sh 检查语法,再执行 bash backup.sh ~/linux-lab/source ~/linux-lab/backup,重复执行应得到不同归档。把归档解到新的空目录,对比文件内容。
失败场景
源不存在应非零退出;目标在源内部应拒绝;目标不可写时应报错且不留下正式归档。源在打包期间变化可能导致 tar 报错或不一致,重要业务需协调写入。gzip/tar 校验仅证明格式可读,真正恢复还要比较数据。
退出码与引号
引号保护路径空格,-- 防止路径被当选项,pipefail 保护管道状态。set -e 有上下文例外,不能代替所有显式错误处理。这里的备份是基础练习,不含数据库、跨主机复制或自动恢复。
内容复核与修订:2026-10-29。实验示例与本站运行记录分别说明;原始归档日期保留。
评论 (0)