rsync,删除接收端已在发送端删除的文件。 (但不要删除所有内容)

rsync,删除接收端已在发送端删除的文件。 (但不要删除所有内容)

我想使用 rsync 来...

  • 删除接收端也已在发送端删除的文件
  • 不删除接收端rsynced目录中的其他文件

例如,假设我有一个目录local-src

前: local-src本地包含...

a.txt
b.txt
c.txt

我想要同步到local-srcto 内容的远程目录称为remote-src.

前: remote-src远程包含...

a.txt
b.txt
c.txt
d.txt
README.md

假设我删除了一些文件local-src

本地删除后: local-src本地包含...

c.txt

如何使用 rsync 确保在源处删除的文件也在目标处删除,但不删除目标处的其他文件。例如,我希望在目的地有以下内容:

本地删除后: remote-src远程包含...

c.txt
d.txt
README.md

也就是说,a.txtb.txt也被远程删除,但d.txtREADME.txt被单独保留。

有什么办法可以用 rsync 来实现这一点吗?

编辑:结论似乎是 rsync 不可能做到这一点。有人问我为什么需要这个,所以为了说明我的用例:

假设我有一个网络服务器。在该网络服务器上,我有一堆目录,假设我有一个目录A和一个public_html为我的网站提供服务的目录。假设我有一些在目录中生成文件的自动化过程A。我想 rsync(或使用其他工具同步)生成的文件或更新A目录中public_html,而不删除可能位于public_html.我当然不希望 rsync 意外删除我的网站。

如果 rsync 不是这项工作的工具,其他人知道我该怎么做吗?

答案1

你想做的事是合理的,但rsync单独去做就不合理了。所以答案是

原因很简单:rsync不保留每个目录中的内容的历史记录,也无法知道哪些内容需要删除,哪些内容不需要删除。并非没有额外的支持。

你应该问自己为什么喜欢这样做,rsync并把它说得更清楚。还有其他librsync1.so更智能的程序。


有了您不需要的宽松约束rsync,您可以看看rdiff 备份:

mkdir a
touch a/xx
touch a/yy
rdiff-backup a b
ls b 

这显示xxyy位于b.

touch b/zz
rm a/xx
rdiff-backup a b

这显示xxzz位于b.rdiff-backup还保留一个目录rdiff-backup-datab以便您可以回滚任何更改,您应该使用命令定期清除它rdiff-backup。 (该示例使用本地文件来显示目标中的额外数据不会被删除,但 rdiff 备份也可以通过网络运行)。


另一种选择是设置一些分布式版本控制系统(mercurial、bazaar、git)。例如,使用 Mercurial,您可以拥有一个脚本(我使用 Makefile),将所有更改推送到服务器,然后更新那里的签出文件,忽略远程服务器上的任何其他文件(但有未置于修订控制之下)。

在服务器上你会这样做:

hg init
hg add file_list_excluding_that_should_not_should_be_deleted_if_not_on_client
hg commit -m "initial setup"

在客户端:

hg clone ssh://username@server/dir_to_repository

现在,如果您删除客户端上的文件并执行以下操作:

hg commit -m "removed file"
ssh username@server "cd dir_to_repository; hg update --clean"

您删除的文件将在服务器上删除,但任何其他数据(未添加到存储库中)不会被删除。

答案2

我认为如果不明确排除接收端的文件作为 rsync 命令的一部分,这是不可能的。请参阅 rsync 的手册页部分:“PER-DIRECTORY RULES AND DELETE”。

如果没有删除选项,每个目录的规则仅与发送端相关,因此您可以随意排除合并文件本身,而不会影响传输。为了使这变得简单,“e”修饰符为您添加了此排除,如这两个等效命令所示:

          rsync -av --filter=': .excl' --exclude=.excl host:src/dir /dest
          rsync -av --filter=':e .excl' host:src/dir /dest

但是,如果您想在接收端进行删除,并且希望排除某些文件被删除,则需要确保接收端知道要排除哪些文件。最简单的方法是在传输中包含每个目录的合并文件并使用 --delete-after,因为这可以确保接收方在尝试删除任何内容之前获得与发送方相同的排除规则:

          rsync -avF --delete-after host:src/dir /dest

但是,如果合并文件不是传输的一部分,您需要指定一些全局排除规则(即在命令行上指定),或者您需要在接收方。第一个示例如下(假设远程 .rules 文件排除自身):

   rsync -av --filter=’: .rules’ --filter=’. /my/extra.rules’
      --delete host:src/dir /dest

在上面的示例中,extra.rules 文件可以影响传输的双方,但(在发送方)规则服从于从 .rules 文件合并的规则,因为它们是在每个目录合并规则之后指定的。

在最后一个示例中,远程端从传输中排除 .rsync-filter 文件,但我们希望使用自己的 .rsync-filter 文件来控制接收端删除的内容。为此,我们必须专门排除每个目录的合并文件(以便它们不会被删除),然后将规则放入本地文件中以控制其他不应删除的内容。就像这些命令之一:

       rsync -av --filter=':e /.rsync-filter' --delete \
           host:src/dir /dest
       rsync -avFF --delete host:src/dir /dest

答案3

如果我理解正确,那么--exclude可能就是您正在寻找的:

$ ls src dst
dst:
a.txt  b.txt  c.txt  d.txt  README.md

src:
c.txt
$ rsync --update --delete --recursive --exclude="d.txt" --exclude="README.md" src/ dst
$ ls src dst
dst:
c.txt  d.txt  README.md

src:
c.txt

答案4

我对此有一个答案。我认为它有效。这对我有用。首先,您应该将rsync远程文件传输到本地文件。然后本地端包含所有文件。

sudo rsync -r -a -v --delete /[email protected]:/remote_dir/ /local_dir/

现在在当地

a.txt
b.txt
c.txt
d.txt
README.md

然后您可以删除文件或执行任何您想要的操作。(在本地端)。在你的问题中,你删除了这些文件。

已删除的文件

a.txt
b.txt

之后您可以将rsync本地文件传输到远程端。这样双方就有了相同的文件。

sudo rsync -r -a -v --delete /local_dir/ [email protected]:/remote_dir/

它给

c.txt
d.txt
README.md

远程端和本地端的文件。(通过使用--delete,可以删除远程端和本地端的其他文件远端不匹配的本地端)。

相关内容