rsync
rsync 是一个开源实用程序,提供快速的增量文件传输。
安装
源机器和目标机器上都必须安装 rsync。
前端
- Grsync — GTK 前端。
- luckyBackup — 用 C++ 编写的 Qt 前端。
- nbRsync — 集成定时任务的 JavaFX rsync 图形界面。
其他使用 rsync 的工具包括 rdiff-backupAUR, osyncAUR 和 yarsyncAUR。
作为 cp/mv 的替代方案
rsync 可以作为 cp 或 mv 命令的高级替代品,特别是在复制大型文件时。
$ rsync -P source destination
-P 选项等同于 --partial --progress,它会保留部分传输的文件并显示进度条。
你可能需要使用 -r/--recursive 选项来递归处理目录。
文件可以像 cp 一样在本地复制,但 rsync 的主要目的在于远程复制文件,即在两台不同主机之间。远程位置可以使用“主机:路径”的语法指定。
$ rsync source host:destination
或者
$ rsync host:source destination
网络文件传输默认使用 SSH 协议,host 可以是实际主机名,也可以是 .ssh/config 中预定义配置文件的别名。
无论是本地还是远程传输,rsync 首先会创建一个文件列表,其中包含信息(默认是文件大小和最后修改时间戳),随后将这些信息用于确定是否需要重构文件。对于需要重构的每一个文件,会针对所有 S 字节长的非重叠数据块计算弱校验和与强校验和,这些数据块的偏移量必须能被 S 整除。利用这些信息,rsync 无需传输整个文件即可重构大文件。更详细的实践与数学解释,请分别参考 rsync 如何工作 和 rsync 算法。
为了快速使用合理的默认值,可以使用一些别名:
cpr() {
rsync --archive -hh --partial --info=stats1,progress2 --modify-window=1 "$@"
}
mvr() {
rsync --archive -hh --partial --info=stats1,progress2 --modify-window=1 --remove-source-files "$@"
}
-hh:以人类可读格式输出数字--info=stats1,progress2:stats1显示详细程度为 1 的 rsync 传输统计信息。progress2打印总体传输进度,而不是每个文件的传输进度(progress1)--modify-window=1:比较两个文件的时间戳时,如果时间戳差异小于 1 秒,则视为相等--remove-source-files:文件成功同步后从源目录移除
--checksum 选项的行为并不等同。--checksum 选项会影响文件传输前使用的文件跳过启发式算法。无论是否使用 --checksum,基于数据块的文件重构(即 rsync 传输文件的方式)始终会使用校验和。尾部斜杠注意事项
Arch 默认使用 GNU cp(GNU coreutils 的一部分)。然而,rsync 遵循 BSD cp 的约定,对带有尾部斜杠“/”的源目录有特殊处理。而
$ rsync -r source destination
将创建一个目录 "destination/source" 并包含 "source" 的内容,但命令
$ rsync -r source/ destination
会将 "source/" 中的所有文件直接复制到 "destination" 中,中间不会创建子目录——就好像你执行了
$ rsync -r source/. destination
这种行为与 GNU cp 不同,GNU cp 将 "source" 和 "source/" 视为相同(但 "source/." 不同)。此外,有些 Shell 在进行目录名自动补全时会自动添加尾部斜杠。由于这些因素,新用户或偶尔使用 rsync 的用户可能会忘记 rsync 的这种行为,通过在命令行留下尾部斜杠,无意中搞乱文件结构甚至覆盖重要文件。
因此,使用一个包装脚本在调用 rsync 前自动移除尾部斜杠是比较审慎的做法。
#!/bin/bash
new_args=()
for i in "${@}"; do
case "${i}" in
/)
i="/"
;;
*/)
i="${i%/}"
;;
esac
new_args+=("${i}")
done
exec rsync "${new_args[@]}"
可以将此脚本放入 PATH 中的某处,并在 Shell 初始化文件中将其 alias 给 rsync。
作为备份工具
rsync 协议可以轻松用于备份,仅传输自上次备份以来发生变化的文件。本节介绍一个使用 rsync 的极其简单的定时备份脚本,通常用于备份到可移动介质。
自动备份
为了方便说明,此脚本创建在 /etc/cron.daily 目录中,如果安装并正确配置了 cron 守护进程,它将每天运行。配置和使用 cron 超出了本文的范围。
首先,创建一个包含合适命令选项的脚本:
/etc/cron.daily/backup
#!/bin/sh rsync -a --delete --quiet /path/to/backup /location/of/backup
-a:表示以归档模式进行归档,意味着保留文件的大多数特性(但不包括 ACL、硬链接或如 capabilities 等扩展属性)--delete:表示在源端删除的文件也将在备份中删除
此处,/path/to/backup 应更改为需要备份的内容(例如 /home),而 /location/of/backup 是保存备份的位置(例如 /media/disk)。
最后,脚本必须是可执行的。
通过 SSH 进行自动备份
如果使用 SSH 备份到远程主机,请改用此脚本:
/etc/cron.daily/backup
#!/bin/sh rsync -a --delete --quiet -e ssh /path/to/backup remoteuser@remotehost:/location/of/backup
-e ssh:告知 rsync 使用 SSHremoteuser:是remotehost主机上的用户名-a:组合了所有这些选项-rlptgoD(递归、链接、权限、时间、组、所有者、设备)
-a 选项)时,需要对目标机器的 root 访问权限。实现此自动化的首选方法是配置 SSH 守护进程,允许 root 使用无密码公钥登录,并以 root 身份运行 rsync 命令。通过 NetworkManager 进行自动备份
此脚本在网络连接建立时启动备份。
首先,创建一个包含合适命令选项的脚本:
/etc/NetworkManager/dispatcher.d/backup
#!/bin/sh
if [ x"$2" = "xup" ] ; then
rsync --force --ignore-errors -a --delete --bwlimit=2000 --files-from=files.rsync /path/to/backup /location/of/backup
fi
-a:组合了所有这些选项-rlptgoD:递归、链接、权限、时间、组、所有者、设备--files-from:从此文件中读取/path/to/backup的相对路径--bwlimit:限制 I/O 带宽;单位为每秒千字节
脚本必须由 root 所有(详细信息请参阅 NetworkManager#Network services with NetworkManager dispatcher)。
通过 systemd 和 inotify 进行自动备份
- 由于 inotify 和 systemd 的限制(见此问答),无法进行递归文件系统监控。虽然你可以监视一个目录及其内容,但它不会递归进入子目录并监视其内容;你必须显式指定每一个要监视的目录,即使该目录是已监视目录的子目录。
- 此设置基于 systemd/User 实例。
与其使用 cron 等基于时间表的方案运行定时备份,不如在每次备份文件发生更改时运行一次备份。systemd.path 单元使用 inotify 来监视文件系统,并可以与 systemd.service 文件结合使用,根据文件系统事件启动任何进程(在本例中为你的 rsync 备份)。
首先,创建将监视要备份文件的 systemd.path 单元:
~/.config/systemd/user/backup.path
[Unit] Description=Checks if paths that are currently being backed up have changed [Path] PathChanged=%h/documents PathChanged=%h/music [Install] WantedBy=default.target
然后创建一个在检测到更改时会被激活的 systemd.service 文件。默认情况下,与 path 单元同名的服务文件(在本例中为 backup.path)会被激活,只需将扩展名 .path 改为 .service 即可(在本例中为 backup.service)。
Type=oneshot。这允许你指定多个 ExecStart= 参数(每个 rsync 命令对应一个)依次执行。或者,你也可以简单地编写一个脚本来执行所有备份,就像 cron 脚本一样。~/.config/systemd/user/backup.service
[Unit] Description=Backs up files [Service] ExecStart=/usr/bin/rsync %h/./documents %h/./music -CERrltm --delete ubuntu:
现在,你只需像普通 systemd 服务一样启用/启动 backup.path,它就会开始监视文件更改并自动启动 backup.service。
每周差异备份
这是 rsync 的一个有用选项,它能实现每次运行都进行全量备份,并只在每周每一天的单独目录中保留已更改文件的差异备份副本。
首先,创建一个包含合适命令选项的脚本:
/etc/cron.daily/backup
#!/bin/sh DAY=$(date +%A) if [ -e /location/to/backup/incr/$DAY ] ; then rm -fr /location/to/backup/incr/$DAY fi rsync -a --delete --quiet --inplace --backup --backup-dir=/location/to/backup/incr/$DAY /path/to/backup/ /location/to/backup/full/
--inplace 选项隐含了 --partial,并会就地更新目标文件。
快照备份
相同的思路可用于维护文件的快照树,即一个包含按日期排序的文件副本的目录。这些副本通过硬链接制作,意味着只有发生更改的文件才会占用空间。总的来说,这就是 Apple TimeMachine 背后的理念。
此基础脚本易于实现,并利用 --link-dest 选项对未更改的文件进行硬链接,从而创建快速的增量快照:
/usr/local/bin/snapbackup.sh
#!/bin/sh
# Basic snapshot-style rsync backup script
# Config
OPT="-aPh"
LINK="--link-dest=/snapshots/username/last/"
SRC="/home/username/files/"
SNAP="/snapshots/username/"
LAST="/snapshots/username/last"
date=`date "+%Y-%b-%d:_%T"`
# Run rsync to create snapshot
rsync $OPT $LINK $SRC ${SNAP}$date
# Remove symlink to previous snapshot
rm -f $LAST
# Create new symlink to latest snapshot for the next backup to hardlink
ln -s ${SNAP}$date $LAST
必须已经存在一个指向完整备份的符号链接,作为 --link-dest 的目标。如果删除了最新的快照,则需要重新创建该符号链接以指向最新的快照。如果 --link-dest 没有找到有效的符号链接,rsync 将会复制所有源文件,而不是仅复制更改的部分。
一个更复杂的版本会保持一个最新的完整备份 $SNAP/latest,如果在上次完整备份后有一定数量的文件发生了变化,它会利用 cp -al 对未更改的文件进行硬链接,创建当前完整备份的快照 $SNAP/$DATETAG:
/usr/local/bin/rsnapshot.sh
#!/bin/sh
## my own rsync-based snapshot-style backup procedure
## (cc) marcio rps AT gmail.com
# config vars
SRC="/home/username/files/" #dont forget trailing slash!
SNAP="/snapshots/username"
OPTS="-rltgoi --delay-updates --delete --chmod=a-w"
MINCHANGES=20
# run this process with real low priority
ionice -c 3 -p $$
renice +12 -p $$
# sync
rsync $OPTS $SRC $SNAP/latest >> $SNAP/rsync.log
# check if enough has changed and if so
# make a hardlinked copy named as the date
COUNT=$( wc -l $SNAP/rsync.log|cut -d" " -f1 )
if [ $COUNT -gt $MINCHANGES ] ; then
DATETAG=$(date +%Y-%m-%d)
if [ ! -e $SNAP/$DATETAG ] ; then
cp -al $SNAP/latest $SNAP/$DATETAG
chmod u+w $SNAP/$DATETAG
mv $SNAP/rsync.log $SNAP/$DATETAG
chmod u-w $SNAP/$DATETAG
fi
fi
为了让事情变得极其简单,此脚本可以从 systemd/Timers 单元运行。
全系统备份
本节介绍使用 rsync 传输整个 / 树的副本,同时排除少数选定的目录。这种方法被认为比使用 dd 进行磁盘克隆更好,因为它允许使用不同的大小、分区表和文件系统;也比使用 cp -a 更好,因为它能更好地控制文件权限、属性、访问控制列表 (ACL) 和扩展属性。
rsync 甚至可以在系统运行时工作,但传输过程中发生更改的文件可能无法被准确传输,这可能会导致使用这些文件的某些程序出现未定义的行为。为减轻风险,请注销所有用户并关闭所有程序和数据库。
这种方法非常适合将现有安装迁移到新硬盘或 SSD。
以 root 身份运行以下命令,以确保 rsync 可以访问所有系统文件并保留所有权:
# rsync -aAXHv --exclude='/dev/*' --exclude='/proc/*' --exclude='/sys/*' --exclude='/tmp/*' --exclude='/run/*' --exclude='/mnt/*' --exclude='/media/*' --exclude='/lost+found/' / /path/to/backup
通过使用 -aAX 选项集,文件将以归档模式传输,这确保了符号链接、设备、权限、所有权、修改时间、ACL 和扩展属性都得到保留(前提是目标文件系统支持该功能)。-H 选项保留硬链接,但会消耗更多内存。
--exclude 选项会导致匹配给定模式的文件/目录被排除。或者结合使用 --exclude-from=file 选项,排除文件中匹配模式(每行一个)的文件/目录,这类似于 #过滤规则的高级用法 中描述的示例,但无需 +/- 语法。
上述命令中包含了 /dev、/proc、/sys、/tmp 和 /run 目录,但这些目录的内容被排除了。这是因为它们在启动时会被填充,但目录本身并不会被创建。/lost+found 是文件系统特定的。引用 exclude 模式将避免被 shell 展开,这在通过 SSH 备份时是必要的。以 * 结尾的排除路径确保了如果这些目录尚不存在,则会创建它们。
- 如果你计划将系统备份到
/mnt或/media之外的地方,请不要忘记将其添加到排除模式列表中,以避免无限循环。 - 如果系统中存在任何绑定挂载(bind mount),也应该排除它们,以便绑定的内容只被复制一次。
- 如果你使用 交换文件,请务必将其排除。
- 考虑是否要备份
/home/目录。如果它包含你的数据,它可能比系统大得多。否则,请考虑排除不重要的子目录,例如/home/*/.thumbnails/*、/home/*/.cache/mozilla/*、/home/*/.cache/chromium/*和/home/*/.local/share/Trash/*(取决于系统中安装的软件)。 - 如果安装了 GVFS,必须排除
/home/*/.gvfs以防止 rsync 出错。 - 如果安装了 Dhcpcd ≥ 9.0.0,请排除
/var/lib/dhcpcd/*目录,因为它在那里挂载了几个系统目录作为子目录。
你可能想要包含额外的 rsync 选项,或移除一些选项。请参阅 rsync(1) 获取完整列表。
- 如果你运行的系统内存非常小,请考虑移除
-H选项;但在大多数现代机器上这应该不成问题。根据所使用的软件,文件系统上可能有许多硬链接(例如如果你在使用 Flatpak)。许多硬链接位于/usr/目录下。 - 如果你多次运行此命令到同一个备份目录,可以考虑添加 rsync 的
--delete选项。在这种情况下,确保源路径不以/*结尾,否则此选项仅对源目录子目录内的文件生效,对源目录内直接的文件无效。 - 如果你使用任何稀疏文件(sparse files),例如虚拟磁盘、Docker 镜像等,你应该添加
-S选项。 --numeric-ids选项将禁用用户和组名的映射;取而代之的是传输数字组 ID 和用户 ID。这在通过 SSH 备份或使用 Live 系统备份不同系统磁盘时非常有用。- 选择
--info=progress2选项而不是-v,将显示整体进度信息和传输速度,而不是正在传输的文件列表。 - 若要在递归时避免跨越文件系统边界,请添加
-x/--one-file-system选项。这将防止备份层级中的任何挂载点。
还原备份
如果你希望还原备份,请使用相同的 rsync 命令,但反转源和目标(你可能还需要在源路径后添加尾部斜杠)。如果你使用了 --exclude 选项,在还原命令中应该将其移除。
过滤规则的高级用法
rsync 可以从单个过滤文件中读取所有包含和排除规则,而不是分开指定。rsync 会按从上到下的顺序处理规则;第一个匹配的规则生效。
backup.filter
# Exclude patterns - .thumbnails/*** - node_modules/*** - venv/*** # Include patterns + /Documents/*** + /Books/*** + /Music/*** # Exclude everything else - /**
*** 是一个特殊的 rsync 模式,它匹配文件夹及其所有递归内容。
查看 rsync(1) § PATTERN MATCHING RULES 和 rsync(1) § FILTER RULES IN DEPTH 获取更多详情。
然后运行 rsync:
$ rsync -aAXHv --filter="merge backup.filter" $SRC $DEST
关键字是 --filter "merge ..." 参数,它会读取过滤文件并为每个同步的文件解析规则。
从路径列表复制
除了 #过滤规则的高级用法 方法外,还可以使用 --files-from 选项。它可以读取包含目录或文件路径列表的文本文件,每个条目换行分隔。需要注意的是,如果用户希望递归复制目录,即使已经包含了 -a,也必须手动为该选项指定 -r 标志。
例如,可以通过以下命令存档目录列表及其递归目录:
$ rsync -aAXHvr --files-from="dir_list.txt" $SRC $DEST
文件系统克隆
rsync 提供了一种方式,可以在尽可能保留信息(包括文件系统元数据)的情况下,复制文件系统中的所有数据。这是一个文件系统级别的数据克隆过程,源文件系统和目标文件系统不需要是同一种类型。它可以用于备份、文件系统迁移或数据恢复。
rsync 的 归档 模式几乎可以胜任这项工作,但它不会备份特殊的文件系统元数据,如访问控制列表 (ACL)、扩展属性或稀疏文件属性。为了在文件系统级别成功克隆,需要提供一些额外的选项:
rsync -qaAXHSU SOURCE_DIR DESTINATION_DIR
它们的含义(摘自 man 手册页):
--acls, -A preserve ACLs (implies --perms) --xattrs, -X preserve extended attributes --hard-links, -H preserve hard links --sparse, -S turn sequences of nulls into sparse blocks --atimes, -U preserve access (use) times
此外,如果你有挂载在树下的其他文件系统,并且想要将它们从副本中排除,请使用 -x。
- 如果你使用 rsync 将 Arch 安装迁移到新驱动器,请记住在
SOURCE_DIR的末尾包含一个尾部斜杠,原因在 #尾部斜杠注意事项 中提到。 - 创建时间(
crtime)将不会被保留。虽然有一个-N/--crtimes标志用于此,但在 Linux 上不受支持。
生成的副本可以在文件系统级别通过 diff 的递归选项简单地重新读取和检查(例如在数据恢复尝试之后):
diff -r SOURCE_DIR DESTINATION_DIR
可以通过使用本文所述的 rsync 方法,并按照 Migrate installation to new hardware 所述更新 fstab 和 引导加载程序,来成功进行文件系统迁移。这实质上提供了一种将任何根文件系统转换为另一个文件系统的方法。
作为守护进程
rsync 可以作为监听 TCP 端口 873 的服务器守护进程运行。
编辑模板 /etc/rsyncd.conf,配置一个共享并启动 rsyncd.service。
rsyncd.service 和 rsyncd@.service。有关 ProtectHome 的更改已被注释,[Service] 部分下的安全功能 ProtectSystem=full 仍然处于活动状态。这使得 /boot/、/etc/ 和 /usr/ 目录变为只读。如果你需要 rsyncd 写入系统目录,你可以编辑该单元,并在重写片段的 [Service] 部分中设置 ProtectSystem=off。客户端用法,例如列出服务器内容:
$ rsync rsync://server/share
从客户端传输文件到服务器:
$ rsync local-file rsync://server/share/
考虑在防火墙中打开 TCP 端口 873,并使用用户身份验证。
示例配置
共享文件列表
/etc/rsyncd.conf
...
# Needed when crossing filesystem boundaries.
#use chroot = no
read only = yes
...
[sync]
path = /
# List of files to copy.
include from = /backup.list
# Exclude the rest.
exclude = *
在文件列表中,所有中间路径都是必要的,除非使用了 *** 通配符。
/backup.list
/etc/ /etc/conf.d/ /etc/conf.d/hwclock /etc/fonts/***
参见
- 更多使用示例可以在 社区贡献 (Community Contributions) 和 通用编程 (General Programming) 论坛中搜索。
- Howto – 使用带有硬链接的 rsync 进行本地和远程快照备份 包括硬链接文件去重、MD5 完整性签名、'chattr' 保护、过滤规则、磁盘配额、具有指数分布的保留策略(在保存更多近期备份的同时进行备份轮转)。
- 在 rsync 中使用 SSH 密钥/身份文件
- rrsync(1) 是一个通过 SSH 登录设置受限 rsync 用户的脚本。它包含在 rsync 包中。更多详细信息和示例请参见 OpenSSH#Restrict。