如何使用 rsync 包含和排除来捕获分布式文件集?

如何使用 rsync 包含和排除来捕获分布式文件集?

我正在尝试使用 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语句都将覆盖exclude1。

我会添加-v标志 ( --verbose),这样我就可以看到正在发生的事情,以及-n用于测试的标志 ( )。您可以立即看到,除了可能的和 之外,--dry-run您没有包含任何文件:erikfoobarbaz

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

相关内容