同步单个文件并保持N级文件夹结构

时间:2013-12-13 20:23:07

标签: rsync

我有以下结构:

/Users
  /build
    /.jenkins
      /jobs
         /Job1
           config.xml
           someotherfiles.blah
         /Job2
           config.xml
           someotherfiles.blah
         /JobN
           config.xml
           someotherfiles.blah

我想只将config.xml文件备份到另一个文件夹,保持新文件夹中的文件夹结构相同,但要删除/User/build/.jenkins/jobs

我的新文件夹如下所示:

backup/
  /Job1
    config.xml
  /Job2
    config.xml
  /JobN
    config.xml

这可以使用rsync吗?

编辑:意外地在输出中包含了 someotherfiles.blah ,实际上我不想要那些。我想要的只是config.xml文件以及文件夹结构1级。

3 个答案:

答案 0 :(得分:3)

这应该有效:

rsync -r --include=Job* --include=config.xml --exclude=* /full/path/to/Users/build/.jenkins/ backup

除非将-R选项传递给rsync,否则不会将完整路径复制到备份目录。如果您添加Job*config.xml,然后排除*(订单很重要,因为首次匹配包含或排除规则会确定要复制的内容),您最终得到的结构是想。如果明确的Job*模式限制太多,手册说您应该能够使用*/模式:

  

一种解决方案是要求层次结构中的所有目录   使用单一规则包含:“+ * /”(将其放在“ - *”规则之前的某处)

有关详细信息,请参阅手册页的整个“INCLUDE / EXCLUDE PATTERN RULES”部分。

答案 1 :(得分:2)

您可以使用--relative选项指定文件夹级别。

从手册:

  

还可以限制作为指定的每个路径的隐含目录发送的路径信息量。使用发送端的现代rsync(从2.6.7开始),您可以在源路径中插入一个点和一个斜杠,如下所示:

rsync -avR /foo/./bar/baz.c remote:/tmp/

在此示例中,--relative选项将开始从第二级创建文件夹。在遥控器上:

/tmp
|_ bar
   |_ baz.c

答案 2 :(得分:1)

你走了:

find ./build/.jenkins/jobs/* | 
grep -i 'someotherfiles.blah' | 
cut -d / -f 5- |
rsync -v -r --exclude-from=- ./build/.jenkins/jobs/ ./output

在步骤中,这就是正在发生的事情:

 find ./build/.jenkins/jobs/*

这提供了指定路径中的目录/文件列表。它的输出是

./build/.jenkins/jobs/Job1
./build/.jenkins/jobs/Job1/config.xml
./build/.jenkins/jobs/Job1/someotherfiles.blah
./build/.jenkins/jobs/Job2
./build/.jenkins/jobs/Job2/config.xml
./build/.jenkins/jobs/Job2/someotherfiles.blah
./build/.jenkins/jobs/Job3
./build/.jenkins/jobs/Job3/config.xml
./build/.jenkins/jobs/Job3/someotherfiles.blah

然后我们将它传递给grep命令,在那里我们可以放入我们想要过滤的任何模式。在我的例子中,我想要排除someotherfiles.blah

find ./build/.jenkins/jobs/* | 
grep -i 'someotherfiles.blah'

输出

./build/.jenkins/jobs/Job1/someotherfiles.blah
./build/.jenkins/jobs/Job2/someotherfiles.blah
./build/.jenkins/jobs/Job3/someotherfiles.blah

现在rsync将从stdin获取要从其同步中排除的模式列表。它需要有相对于其src参数的路径,所以我们从列表中删除了前几个目录。

find ./build/.jenkins/jobs/* | 
grep -i 'someotherfiles.blah' | 
cut -d / -f 5-

输出:

Job1/someotherfiles.blah
Job2/someotherfiles.blah
Job3/someotherfiles.blah

现在我们使用--exclude-from = - 参数将其传递给它rsync。这将告诉它从stdin中排除文件。

find ./build/.jenkins/jobs/* | 
grep -i 'someotherfiles.blah' | 
cut -d / -f 5- |
rsync -v -r --exclude-from=- ./build/.jenkins/jobs/ ./output

输出

building file list ... done
Job1/
Job1/config.xml
Job2/
Job2/config.xml
Job3/
Job3/config.xml

sent 318 bytes  received 104 bytes  844.00 bytes/sec
total size is 15  speedup is 0.04

此解决方案使用grep从rsync中查找要EXCLUDE的文件列表。您可能希望grep表达式仅对某些文件进行INCLUDE。您也可以使用--include-from = - 参数执行此操作。还有一个变化。以下是完整代码,仅复制config.xml文件

find ./build/.jenkins/jobs/ | 
grep -i 'config.xml' | 
cut -d / -f 5- |
awk -F/ '{print; while(/\//) {sub("/[^/]*", ""); print}}'| 
rsync -v -r --include-from=- --exclude='*' ./build/.jenkins/jobs/ ./output

当您向--exclude列表添加内容时,rsync将不会搜索列表的任何子目录。显然,我们不希望这样,因为我们的Job1,2,3文件夹中有config.xml文件!因此,我们使用awk将我们要搜索config.xml文件的父目录添加到输出中。

之后,我们告诉rsync来自我们的stdin,并且排除其他所有内容('*')

上面的路径使用相对路径,如果使用绝对路径,则根据需要修改路径,并确保cut命令中的-f参数选择要切割的正确的令牌编号。

无论如何,将这些命令保存在.sh文件中,你应该有一个方便的小实用工具。