rsync 同步:参数怎么选才不出事
rsync 是服务器上最常用的同步工具,也是最容易因为一个参数误删数据的工具。搞清楚几个关键点再用。
一、-a 包含什么
rsync -a src/ dst/
# -a = -rlptgoD
# -r 递归目录
# -l 保留软链接
# -p 保留权限
# -t 保留修改时间
# -g 保留属组
# -o 保留属主
# -D 保留设备文件、特殊文件常用组合:
| 组合 | 用途 |
|---|---|
-av | 归档 + 显示过程(最常用) |
-avz | 加压缩,跨网络传输用 |
-avP | -P = --partial --progress,大文件断点续传 + 进度 |
-avn | -n = --dry-run,只预演不执行 |
异地备份我固定用
rsync -avzP,本地同步用rsync -av。
二、结尾斜杠:最容易搞错的地方
这一个字符的差别,决定了目录结构完全不同:
rsync -av /data/www /backup/ # 结果:/backup/www/...(连目录一起)
rsync -av /data/www/ /backup/ # 结果:/backup/...(只同步内容)| 源路径 | 效果 |
|---|---|
src (无斜杠) | 把 src 目录本身复制过去 |
src/(有斜杠) | 把 src 里面的内容复制过去 |
目标路径的斜杠影响不大,但建议统一加上。
镜像一个目录的标准写法:
rsync -av --delete /var/www/baize/ /backup/baize/三、--delete:强大且危险
--delete 会删除目标端「源端没有的文件」,让两边完全一致。
危险场景:
# 源目录拼错或被清空 → 目标被清空
rsync -av --delete /var/www/typo/ /backup/baize/ # 灾难安全措施:
# 1. 永远先 --dry-run 看会删什么
rsync -av --delete --dry-run src/ dst/
# 2. 加备份目录,被删的文件先移过去
rsync -av --delete --backup --backup-dir=/backup/deleted-$(date +%F) src/ dst/
# 3. 限制删除量,超量就中止(很实用)
rsync -av --delete --max-delete=100 src/ dst/我的规则:带
--delete的命令,必须先跑一遍--dry-run,看输出里 deleting 的行数是否合理。
四、排除文件
rsync -av --exclude "*.log" --exclude "node_modules/" src/ dst/
# 从文件读排除列表
rsync -av --exclude-from=/etc/rsync-exclude.txt src/ dst/# /etc/rsync-exclude.txt
*.log
*.tmp
node_modules/
.git/
cache/
__pycache__/
.DS_Store
--exclude的路径是相对于传输根的,写绝对路径不生效。这是常见困惑点。
五、远程同步
# 推到本地 → 远程
rsync -avzP /data/ user@host:/backup/
# 拉:远程 → 本地
rsync -avzP user@host:/var/www/ /local/copy/
# 指定 SSH 端口和密钥
rsync -avzP -e "ssh -p 2222 -i ~/.ssh/id_ed25519" /data/ user@host:/backup/
# 限速(避免打满带宽,单位 KB/s)
rsync -avzP --bwlimit=2000 /data/ user@host:/backup/六、增量备份:--link-dest
想要「每次备份看起来都是完整副本,但只占增量空间」,用硬链接:
#!/usr/bin/env bash
set -euo pipefail
SRC="/var/www/baize/"
BASE="/backup/baize"
TODAY="$BASE/$(date +%F)"
LAST="$BASE/last"
mkdir -p "$BASE"
if [ -e "$LAST" ]; then
# 与上次相同的文件做成硬链接,不占额外空间
rsync -av --delete --link-dest="$LAST" "$SRC" "$TODAY"
else
rsync -av "$SRC" "$TODAY"
fi
rm -f "$LAST"
ln -s "$TODAY" "$LAST"
# 清理 30 天前的
find "$BASE" -maxdepth 1 -type d -mtime +30 -exec rm -rf {} +效果:每天一个完整目录,实际磁盘只增加了变化的部分。
# 看起来占了很多,其实共享文件
du -sh /backup/baize/* # 每个都是几十 G
du -sh /backup/baize # 总量只略大于一份七、校验而不是信任
# -c 按校验和比较(默认按大小和时间,慢但准)
rsync -avc src/ dst/
# 只看差异不传输
rsync -avn --itemize-changes src/ dst/
# 输出里的符号含义
# >f+++++++++ 新增文件
# >f..t...... 时间戳变了
# >f.s...... 大小变了
# .d 目录
# *deleting 要删除八、常见问题
| 现象 | 原因 / 解法 |
|---|---|
| 权限被拒绝 | 目标目录属主不对,或用 sudo |
| 传输很慢 | 加 -z(小文件多时反而不快)、检查带宽 |
| 中文文件名乱码 | 加 --iconv=utf8,utf8(老系统) |
| 每次都全量传 | 时间/权限没保留,缺 -a 中的 -t |
| 中断后重来 | 加 -P 支持续传 |
# 保留 ACL 和扩展属性(需要时)
rsync -avAX src/ dst/九、一份日常同步脚本
#!/usr/bin/env bash
# sync-web.sh
set -euo pipefail
SRC="/var/www/baize/"
DEST="backup@10.0.0.2:/backup/baize/"
LOG="/var/log/rsync-baize.log"
echo "[$(date '+%F %T')] 开始同步" >> "$LOG"
rsync -avzP --delete \
--exclude-from=/etc/rsync-exclude.txt \
--bwlimit=5000 \
-e "ssh -p 2222 -o StrictHostKeyChecking=accept-new" \
"$SRC" "$DEST" >> "$LOG" 2>&1
if [ $? -eq 0 ]; then
echo "[$(date '+%F %T')] 同步完成" >> "$LOG"
else
echo "[$(date '+%F %T')] 同步失败!" >> "$LOG"
exit 1
firsync 记住三句:先 --dry-run、源路径带斜杠表示内容、--delete 要配 --backup-dir。
