rsync 使用 include-from 仅同步特定文件或目录

rsync 使用 include-from 仅同步特定文件或目录

这似乎是一个非常简单的请求,但我已经为 rsync 绞尽脑汁大约一个小时了,所以我想问一下。我只是想使用 rsync 将本地目录中的一小组文件列入远程目录中的白名单。

假设现在我只想发送*.ts根目录中的文件。因此,想象一下源结构如下:

/foo
  bar.ts
  baz.ts
  package.json
  node_modules/...
  other_dir/...

在这个例子中,我只想发送bar.tsbaz.ts

我是谁要做的就是:

rsync --include-from include.txt foo remotehost:foo

其中include.txt仅包含:

*.ts

当我尝试这样做时,我明白了skipping directory .为什么如果我有一个include-from列表,会发生这种情况?

因此我尝试使用存档/递归模式(但这不是我想要的,因为我只是想指定一个列表……但无论如何让我们尝试一下):

rsync -a --include-from include.txt foo remotehost:foo

这样就可以复制所有内容foo并忽略include-from

于是我尝试:

rsync -a --exclude '*' --include-from include.txt foo remotehost:foo

我以为这些模式是从左到右进行评估的,所以我希望这只包含我列表中的文件,但它排除了它们,因为它们与模式“*”匹配

再说一次,这看起来是一个非常基本的事情,我不知道为什么让 rsync 做到这一点如此具有挑战性。

我在这里遗漏了什么?

答案1

让我从最简单的解决方案开始,然后解释一下为什么你的尝试没有达到预期效果。试试这个:

rsync foo/*.ts remotehost:foo

请注意,shell 在运行之前会扩展通配符rsync,因此这基本上等同于:

rsync foo/bar.ts foo/baz.ts remotehost:foo

编辑:经过评论中的讨论,我认为根本问题是规则名称“包括”有点误导;称它们为“不要排除“规则,甚至更好”即使过滤列表后面有一条排除规则,也不要排除“(但这些都很冗长,而且对 shell 脚本语法不友好,所以”排除“ 这是)。

这样说吧:告诉-r在源目录内传输文件/子文件夹,“排除”规则允许您对此做出例外(即跳过一些将被传输的项目),而“包含”规则允许您对例外做出例外(即传输以后的“排除”规则将排除的项目)。-arsync

现在,让我们回顾一下那些不起作用的命令:

rsync --include-from include.txt foo remotehost:foo

这里的问题是你告诉它同步目录(foo),而不是文件该目录。使用-r(或-a) 选项,它不会执行此操作,因此它只会跳过该目录。因此,您添加-a

rsync -a --include-from include.txt foo remotehost:foo

...现在它会发送所有内容,因为你给了它一份要包含的内容列表,但没有告诉它要包含哪些内容排除任何东西。默认是包含事物,添加明确的指令来包含特定事物不会改变这一点。

因此你添加一个排除指令:

rsync -a --exclude '*' --include-from include.txt foo remotehost:foo

...但是您首先放置了排除规则,它会从左到右检查规则,并根据第一个匹配项采取行动。由于所有内容都匹配*,因此所有内容都会被排除,并且文件中的包含规则永远不会被应用。

您应该能够通过首先放置包含规则来使其工作:

rsync -a --include-from include.txt --exclude '*' foo remotehost:foo

...但正如我在开头所建议的那样,使用 shell 通配符进行匹配会更容易。尽管你如果您要将文件从远程复制到本地,则需要使用类似这样的方法,因为您的本地 shell 无法应用远程通配符。

答案2

非常感谢 Gordon Davisson 的详细回复。

我最终选择了以下方向,其行为更接近我的预期并且感觉“优雅”:

rsync -aF foo remotehost:foo

作为a存档标志(以递归方式处理foo),并F指示 rsync 它应该.rsync-filter在它检查的每个目录中查找名为的文件。

然后我的.rsync-filter文件最终指定了包含/排除规则:

+ **/*.ts
- node_modules

我喜欢这个解决方案,因为 rsync 已经为这个“过滤器”指定了预期的文件名,所以我不需要编造(并指定)任意的包含/排除文件名。它也是一个简短的单字母标志,因此发出的命令非常易读。

相关内容