rsync 示例:在 Linux 中同步文件与备份
rsync 可在本地及通过 SSH 复制和同步文件,只传输发生变化的部分。基本命令为 rsync -avz 源/ user@host:/路径/:-a 保留权限和时间,-v 显示文件列表,-z 压缩传输数据;--delete 使目标与源完全一致,-n 则可以先试运行、不做任何更改。
rsync 是 Linux 中用于复制和同步文件的标准工具:可用于本地、磁盘之间,也可通过 SSH 在服务器之间使用。它与 cp 和 scp 的主要区别在于只传输发生变化的内容,因此再次同步大型目录往往只需几秒钟。下面是一些常见任务的 rsync 示例:把项目复制到服务器、镜像目录、排除文件、带快照的备份,以及定时运行。
语法与最常用的参数
命令的通用格式:
rsync [选项] 源... 目标
源和目标可以是本地路径,也可以是 user@host:/路径 形式的远程路径。两端中至少有一端是本地的:rsync 不能直接在两台远程机器之间复制。
| 参数 | 作用 |
|---|---|
-a | 归档模式:递归复制,并保留权限、所有者、所属组、修改时间和符号链接(等同于 -rlptgoD) |
-v | 输出被传输的文件列表 |
-z | 在网络传输时压缩数据 |
-h | 以易读的形式显示大小(K、M、G) |
-P | 等同于 --partial --progress:显示进度并支持续传中断的文件 |
-n、--dry-run | 试运行:显示将要执行的操作,但不做任何更改 |
--delete | 删除目标中源端不存在的文件 |
--exclude | 按模式排除文件,不予复制 |
-e | 指定远程 shell,例如 -e "ssh -p 2222" |
-H、-A、-X | 保留硬链接、ACL 和扩展属性(不包含在 -a 中) |
实际使用中,十次有九次只需要本地用 rsync -avh,网络传输用 rsync -avzh。
路径末尾的斜杠:最常见的陷阱
新手最容易犯的错误与源路径末尾的斜杠有关。它决定复制的是目录本身,还是目录中的内容。
# 把 project 目录整体复制到 /backup 中 → 得到 /backup/project/...
rsync -av project /backup/
# 把 project 的内容复制到 /backup 中 → 文件直接位于 /backup/ 下
rsync -av project/ /backup/
记住这一点即可:源路径末尾的斜杠表示“该目录的内容”。目标路径的斜杠不起作用。如果不确定,就加上 -n 查看 rsync 将要创建哪些路径。
本地复制
把目录复制到外接硬盘并显示进度:
rsync -avhP ~/photos/ /mnt/usb/photos/
再次运行同一条命令时不会重新复制全部内容:rsync 会比较文件的大小和修改时间,只传输新增和修改过的文件。命令结束时的输出会显示实际传输了多少数据:
sending incremental file list
2026/10/IMG_2041.jpg
4.12M 100% 38.40MB/s 0:00:00 (xfr#1, to-chk=0/1534)
sent 4.13M bytes received 9.25K bytes 2.76M bytes/sec
total size is 6.82G speedup is 1,648.21
speedup 表示与完整复制相比,传输的数据量少了多少倍。
通过 SSH 使用 rsync:上传到服务器和从服务器下载
对于远程路径,rsync 默认使用 SSH,因此无需额外配置,只要普通的 ssh 登录可用即可。最方便的是使用密钥:这样不会提示输入密码,也可以把命令放入 cron。
# 将网站上传到服务器
rsync -avz ./site/ deploy@203.0.113.10:/var/www/site/
# 从服务器下载日志到本机
rsync -avz deploy@203.0.113.10:/var/log/nginx/ ./nginx-logs/
# SSH 使用非标准端口并指定密钥
rsync -avz -e "ssh -p 2222 -i ~/.ssh/deploy_key" ./site/ deploy@203.0.113.10:/var/www/site/
rsync 需要在两台机器上都安装:远程端是通过 SSH 启动的。如果远程没有安装,会看到 rsync: command not found,此时安装该软件包即可(sudo apt install rsync 或 sudo dnf install rsync)。
如果主机在 ~/.ssh/config 中配置了别名,rsync 同样可以识别:rsync -avz ./site/ prod:/var/www/site/。
服务器上需要 root 权限
当目标文件属于 root,而你以普通用户登录时,可以通过 sudo 运行远程 rsync:
rsync -avz --rsync-path="sudo rsync" ./conf/ admin@server:/etc/myapp/
为此,服务器上的 sudo 必须允许无密码运行 rsync(需在 sudoers 中配置),否则命令会一直等待输入密码。
目录镜像:--delete
默认情况下,rsync 只添加和更新文件,不删除任何内容。要让目标与源完全一致,需要使用 --delete:
rsync -avh --delete ~/projects/ /mnt/backup/projects/
这是一个强大而危险的参数。路径写错(例如源为空,或漏掉斜杠)就可能删除目标中的数据。因此有一条规则:任何带 --delete 的命令,都要先用 -n 运行。
$ rsync -avhn --delete ~/projects/ /mnt/backup/projects/
sending incremental file list
deleting old-app/README.md
deleting old-app/
app/main.py
sent 1.20K bytes received 64 bytes 2.53K bytes/sec
total size is 18.4M speedup is 14,554.39 (DRY RUN)
以 deleting 开头的行表示将被删除的内容。确认无误后,去掉 -n 再执行。
其他有用的变体:--delete-after 在传输完成后再删除文件(目标在过程中保持完整),--backup --backup-dir=/mnt/backup/deleted-$(date +%F) 不直接删除,而是把将被删除或替换的文件移动到单独的目录中。
排除文件:--exclude 与 --include
在部署和备份时排除临时文件、依赖目录和敏感信息是很常见的做法。
# 多个模式
rsync -avz --exclude='.git/' --exclude='node_modules/' --exclude='*.log' ./app/ server:/srv/app/
# 从文件中读取模式
rsync -avz --exclude-from='.rsyncignore' ./app/ server:/srv/app/
.rsyncignore 文件就是一个简单的模式列表,每行一个:
.git/
node_modules/
*.log
.env
tmp/
模式的匹配规则:
- 开头没有斜杠的模式(如
*.log)在任意深度都会匹配。 - 开头有斜杠的模式(如
/tmp/)相对于传输的根目录,只排除顶层的tmp。 - 末尾有斜杠的模式(如
cache/)只匹配目录。 - 规则按顺序检查,以第一条匹配的规则为准。
根据最后一条规则,可以使用“只复制需要的内容”的技巧:先允许需要的文件,再排除其余所有文件。
# 只复制 .conf 文件,并保留目录结构
rsync -av --include='*/' --include='*.conf' --exclude='*' /etc/ ./etc-confs/
这里的 --include='*/' 是为了让 rsync 进入所有子目录。加上 --prune-empty-dirs(-m)可以避免创建空目录。
用 rsync 做备份
简单的每日副本
把主目录最简单地备份到第二块硬盘:
rsync -aH --delete --exclude='.cache/' /home/alice/ /mnt/backup/alice/
这种方式的缺点是只保留一个版本。如果文件被损坏,而备份已经同步了,旧版本也就丢失了。
使用 --link-dest 的增量快照
--link-dest 几乎不占额外空间就能解决这个问题。未更改的文件不会被复制,而是以硬链接的方式指向上一个快照中的文件。每个快照看起来都是完整副本,但实际只占用变化部分的空间。
#!/bin/bash
set -euo pipefail
SRC="/home/alice/"
DEST="/mnt/backup/snapshots"
TODAY="$(date +%F)"
mkdir -p "$DEST"
rsync -aH --delete \
--exclude='.cache/' \
--link-dest="$DEST/latest" \
"$SRC" "$DEST/$TODAY"
ln -sfn "$DEST/$TODAY" "$DEST/latest"
首次运行时还不存在 latest 目录,rsync 会给出警告并完整复制一次,这是正常现象。删除旧快照可以直接使用 rm -rf:被其他快照引用的文件不会丢失。
删除 30 天前的快照可以这样做:
find /mnt/backup/snapshots -maxdepth 1 -type d -name '20*' -mtime +30 -exec rm -rf {} +
把服务器备份到另一台机器
建议由备份机拉取数据(从备份服务器拉到工作服务器),而不是由工作服务器推送。备份机自己获取数据,工作服务器无法访问备份。即使它被入侵,备份依然完好。
rsync -azH --delete -e "ssh -i /root/.ssh/backup_key" \
backup@web01:/var/www/ /srv/backups/web01/www/
注意,数据库不能这样直接复制:正在运行的数据库文件在复制过程中是不一致的。应先导出转储(mysqldump、pg_dump),再用 rsync 传输转储文件。
通过 cron 定时运行
用 crontab -e 将备份脚本加入 cron:
# 每天 03:15 运行,输出写入日志
15 3 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
要让 cron 中的备份真正运行,请检查以下几点:
- 脚本中使用绝对路径:cron 的
PATH很简单,当前目录也不同。 - SSH 密钥无需密码,并且主机已经在
known_hosts中——否则 rsync 会在询问主机真实性时卡住。 - 脚本检查返回码:rsync 成功时返回 0,部分文件未能传输时返回 23,复制过程中文件消失时返回 24。
- 用
flock防止两个备份同时运行:flock -n /tmp/backup.lock /usr/local/bin/backup.sh。
也可以用 systemd 定时器代替 cron:它把输出写入日志,通过 journalctl 查看结果很方便。
大量传输时的实用选项
| 任务 | 选项 |
|---|---|
| 限制速度,避免占满网络 | --bwlimit=5M |
| 连接中断后续传大文件 | -P(或 --partial) |
| 显示总体进度,而不是文件列表 | --info=progress2 |
| 按内容而非时间比较 | -c(--checksum),速度较慢 |
| 不覆盖目标中更新的文件 | -u(--update) |
| 不覆盖已存在的文件 | --ignore-existing |
| 传输后删除源文件(移动) | --remove-source-files |
| 结束时显示详细统计信息 | --stats |
常见错误及解决方法
- 写入时出现
Permission denied——当前用户对目标目录没有权限。检查目录的所有者,或使用--rsync-path="sudo rsync"。 - 每次都重新复制全部文件——修改时间没有被保留。确认使用了
-a或-t;在 FAT/exFAT 上还要加上--modify-window=2,因为这些文件系统的时间精度只有两秒。 - 复制到U盘或网络文件夹时出现
chown或chgrp错误——该文件系统不支持所有者信息。把-a替换为-rlt。 - 出现多余的嵌套
/backup/project/project——源路径末尾的斜杠写错了。 connection unexpectedly closed——SSH 问题,或远程没有安装 rsync。先检查普通的ssh登录,并确认服务器上已安装rsync。
总结
日常工作中只需记住几条命令:用 rsync -avz src/ host:/dst/ 通过 SSH 复制,用 --delete 配合试运行 -n 制作镜像,用 --exclude 排除多余文件,用 --link-dest 制作带快照的备份。注意源路径末尾的斜杠,rsync 就会成为在机器之间传输文件最可靠的方式。同步与备份的实际操作会在 Linux 课程中详细讲解。
常见问题
rsync 相比 scp 有什么优势?
scp 每次都会整体复制文件,而 rsync 只传输变化的部分,还支持续传、删除目标中多余的文件以及按模式排除文件。单次复制一个文件时两者差别不大,但对于定期同步,rsync 快得多。
可以在 Windows 上使用 rsync 吗?
可以,通过 WSL(在其中 rsync 的安装与普通 Linux 相同)或 Cygwin。将 Windows 电脑上的文件同步到 Linux 服务器,在 WSL 中操作最方便。
rsync 会加密传输的数据吗?
rsync 本身不加密,但通过 SSH 复制时,所有流量都经过加密的 SSH 连接。只有使用 rsync:// 地址访问 rsync 守护进程时才是未加密的。
如何检查副本是否与原件完全一致?
运行 rsync -avnc 源/ 目标/——其中 -c 按校验和比较文件,-n 不做任何更改。如果没有输出任何文件列表,说明两者完全相同。
在传输过程中中断 rsync 会怎样?
已经传输完成的文件会保留,未完成的文件默认会被删除。重新运行同一条命令会从中断处继续;加上 -P 参数,已传输的部分还会被保留。