我正在尝试使用 rsync 备份一台机器,在阅读了大量 SO QA 和手册页后,我仍然无法理解包含/排除优先级如何工作,因此我无法传输正确的文件集。为了掩盖具体细节,我尝试执行以下操作:
递归包含:
/home/erik/foo
/home/erik/bar
/home/erik/baz
递归包含 /git,但排除一些特定的子目录,如 /git/src/github.com/foo 和 /git/src/github.com/bar。
到目前为止,我认为 rsync 命令应该可以实现这一点。但事实并非如此,我尝试了多种变体,但都以不同的方式失败了:
rsync -am \
--include='*/' \
--include='/home/erik/foo' \
--include='/home/erik/bar' \
--include='/home/erik/baz' \
--include='/git' \
--exclude='/git/bin' \
--exclude='/git/src/github.com/foo' \
--exclude='/git/src/github.com/bar' \
--exclude='*' \
/ nfs.example.com:/data/pool/backup/laptop
一些具体问题:
我多次看到有人建议初始的 --include='*/ 是必要的,尽管我并不完全清楚为什么。我认为这与确保目录被展开和跟踪有关(?)。我还假设最后的排除是排除任何与更高语句不匹配的文件?有人能详细说明这两者是否都是必要的,以及它们的地位是否重要吗?
我不确定目录是否需要以 / 开头。我看到一些提示,这些路径与请求的传输根 / 有关,这表明它应该是 home/erik 之类的东西,但我也没有成功。有人可以详细说明一下这是如何工作的吗?
如果我想包含目录和所有子内容,我不确定路径中是否需要后缀 /?
有人可以详细说明参数的位置是否真的重要,即列表中第一个匹配的参数是否会被应用?
有什么理由我应该选择 --filter='+ X' 而不是 --include 吗?排除也是一样吗?
答案1
您的命令非常接近可行的解决方案。让我们分解一下,因为我认为这也能回答您的具体问题。
rsync -am
- 还复制明显的文件元数据属性(权限、所有权、时间);不要在目标上创建空目录--include='*/'
- 包含所有目录(尾随/
仅匹配目录)--include='/home/erik/foo'
- 包含此路径(foo
可能是文件或目录;我们无法分辨)--include='/home/erik/bar'
- 同样bar
--include='/home/erik/baz'
- 和baz
--include='/git'
- 包含最顶层git
(前导/
绑定到源树的顶部;我们无法从参数中判断它git
是文件还是目录)--exclude='/git/bin'
bin
- 排除位于最顶层git
目录中的文件或目录(如果是目录,则隐式排除其下的所有内容)--exclude='/git/src/github.com/foo'
-foo
如上所述/git/bin
排除--exclude='/git/src/github.com/bar'
-bar
还有--exclude='*'
- 排除所有我们尚未明确包含的文件或目录/ nfs.example.com:/data/pool/backup/laptop
- 从/
NFS 服务器上的路径复制
首先要记住的是,操作是从左到右(从第一个到最后一个)处理的,第一个匹配的语句获胜。这意味着您的所有include
语句都将覆盖exclude
1。
我会添加-v
标志 ( --verbose
),这样我就可以看到正在发生的事情,以及-n
用于测试的标志 ( )。您可以立即看到,除了可能的和 之外,--dry-run
您没有包含任何文件:erik
foo
bar
baz
rsync --dry-run --verbose --archive --prune-empty-dirs …
**
和通配符***
在这里很有用(**
包括当前点下方的所有文件和目录;***
也适用于当前点本身):
--include='/home/erik/foo/***'
--include='/home/erik/bar/***'
--include='/home/erik/baz/***'
排除git
树的部分内容以及其下的所有相关文件/目录
--exclude='/git/bin/***'
--exclude='/git/src/github.com/foo/***'
--exclude='/git/src/github.com/bar/***'
现在包括(剩下的)git
--include='/git/***'
快完成了。要查找顶层以外的目录和文件,我们必须搜索所有目录,因此让我们包括这些目录,然后使用-prune-empty-dirs
丢弃空目录
--include='*/'
最后,我们可以排除其他一切
--exclude='*'
因此,最终命令是
rsync --dry-run --verbose --archive --prune-empty-dirs \
--include='/home/erik/foo/***' \
--include='/home/erik/bar/***' \
--include='/home/erik/baz/***' \
--exclude='/git/bin/***' \
--exclude='/git/src/github.com/foo/***' \
--exclude='/git/src/github.com/bar/***' \
--include='/git/***' \
--include='*/' \
--exclude='*' \
/ nfs.example.com:/data/pool/backup/laptop