【问题标题】:How to use Rsync to copy only specific subdirectories (same names in several directories)如何使用 Rsync 仅复制特定的子目录(多个目录中的名称相同)
【发布时间】:2013-03-19 05:45:58
【问题描述】:

我在服务器 1 上有这样的目录结构:

  • 数据
    • 公司1
      • unique_folder1
      • 其他文件夹
      • ...
    • 公司2
      • unique_folder1
      • ...
    • ...

我想在服务器 2 上复制这个文件夹结构,但只复制 unique_folder1 的目录/子目录。 IE。结果必须是:

  • 数据
    • 公司1
      • unique_folder1
    • 公司2
      • unique_folder1
    • ...

我知道rsync 非常适合这个。 我尝试了“包含/排除”选项但没有成功。

例如我试过了:

rsync -avzn --list-only --include '*/unique_folder1/**' --exclude '*' -e ssh user@server.com:/path/to/old/data/ /path/to/new/data/

但是,结果,我没有看到任何文件/目录:

receiving file list ... done
sent 43 bytes  received 21 bytes  42.67 bytes/sec
total size is 0  speedup is 0.00 (DRY RUN)

怎么了?想法?


附加信息: 我对两台服务器都有 sudo 访问权限。我有一个想法 - 是使用find 命令和cpio 一起使用我需要的内容复制到新目录,然后使用Rsync。但是这样很慢,文件很多等等。

【问题讨论】:

    标签: centos rsync centos6


    【解决方案1】:

    Andron's Answer 在许多情况下更易于理解和实现的替代方法是使用--files-from=FILE 选项。针对当前的问题,

    rsync -arv --files-from='list.txt' old_path/data new_path/data
    

    list.txt 的位置很简单

    company1/unique_folder1/
    company2/unique_folder1/
    ...
    

    注意-r 标志必须明确包含,因为--files-from 会关闭-a 标志的这种行为。在我看来,路径构造与其他 rsync 命令不同,company1/unique_folder1/ 匹配但/data/company1/unique_folder1/ 不匹配

    【讨论】:

    • 这个方法对我来说要容易得多,因为它允许使用find 来生成要包含的目录列表。
    【解决方案2】:

    例如,如果您只想将target/classes/target/lib/ 同步到远程系统,请执行

    rsync -vaH --delete --delete-excluded --include='classes/***' --include='lib/***' \
          --exclude='*' target/ user@host:/deploy/path/
    

    需要注意的重要事项:

    • 不要忘记路径末尾的“/”,否则您会在子目录中获得副本。
    • --include--exclude 的顺序很重要。
    • 与其他答案相反,以“/”开头的不需要包含/排除参数,它们将自动附加到源目录(示例中为target/)。
    • 要测试究竟会发生什么,我们可以使用 --dry-run 标志,就像其他答案所说的那样。
    • --delete-excluded 将删除目标目录中的所有内容,除了我们特别包含的子目录。应该明智地使用它!因此,一个--delete是不够的,它默认不删除远程端的排除文件(每隔一个,是的),它应该在普通的--delete旁边再次给出。

    【讨论】:

    • 谢谢。那是一个好主意。但在我的例子中,你可以看到我在 X 个不同的目录中有相同的子目录名称。所以,我不确定这是否与您的想法有关。
    • @Andron 是真的。我认为,--include 参数列表应该修改,可能是--include='***/dirName/' 或类似的。我没有对其进行测试,但我的示例来自一个真实的、经过测试的、有效的部署脚本。
    • 这个答案实际上并没有回答这个问题。建议的 --include='***/dirName/' 没有按预期工作。
    • @Marcus 我在 2019 年初使用它,我现在正在使用它,它按预期工作。你能解释一下,究竟什么对你不起作用?
    • 示例如下;没有同步:cd /tmp; mkdir -p data/company{1,2}/{unique_folder1,other_folder}; touch data/company{1,2}/{unique_folder1,other_folder}/testfile; tree data; rsync -vaH --include='***/unique_folder1/' --exclude='*' data/ dest
    【解决方案3】:

    我找到了原因。至于我 - 不清楚Rsync 是否以这种方式工作。
    所以正确的命令(仅适用于company1 目录)必须是:

    rsync -avzn --list-only --include 'company1/' --include 'company1/unique_folder1/***' --exclude '*' -e ssh user@server.com:/path/to/old/data/ /path/to/new/data
    

    即我们需要包含每个父 company 目录。当然我们不能在命令行中手动编写所有这些company目录,所以我们将列表保存到文件中并使用它。


    我们需要做的最后事情:

    1.在服务器1上生成包含文件,所以它的内容是(我用过lsawk):

    + company1/  
    + company1/unique_folder1/***  
    ...  
    + companyN/  
    + companyN/unique_folder1/***  
    

    2.将include.txt复制到服务器2并使用这样的命令:

    rsync -avzn                                        \
          --list-only                                  \
          --include-from '/path/to/new/include.txt'    \
          --exclude '*'                                \
          -e ssh user@server.com:/path/to/old/data/    \
          /path/to/new/data
    

    【讨论】:

    • 嗨,Andron,您使用三个星号有什么原因吗?两个和三个我都试过了,我看不出有什么区别。我现在正在使用这种技术来备份一些文件,谢谢发布。
    • 没关系,我想通了。我在做folder** 而不是folder/***。当您在目录名称后使用斜杠时,您需要第三个星号。两个星号和没有斜线的方法也可以,但不太精确,因为它也会匹配具有相同基本名称的对等文件夹。
    • @ChadvonNau 嗯,不知道为什么我使用了***。在RSync docs 我看到use '**' to match anything, including slashes。所以也许2个星号就足够了。但我认为3更好:)
    • 如果你想排除最顶层的目录,也可以考虑这个unix.stackexchange.com/a/42691/37431
    • 关于三个星号; Rsync 手册页定义... trailing "dir_name/***" will match both the directory (as if "dir_name/" had been specified) and everything in the directory (as if "dir_name/**" had been specified). This behavior was added in version 2.6.7
    【解决方案4】:

    如果第一个匹配模式排除了一个目录,那么它的所有后代将永远不会被遍历。当您想包含一个深层目录时,例如company*/unique_folder1/** 但排除其他所有内容 *,您需要告诉 rsync 也包括其所有祖先:

    rsync -r -v --dry-run                       \
        --include='/'                           \
        --include='/company*/'                  \
        --include='/company*/unique_folder1/'   \
        --include='/company*/unique_folder1/**' \
        --exclude='*'
    

    您可以使用 bash 的大括号扩展来节省一些输入。大括号展开后,下面的命令和上一条完全一样:

    rsync -r -v --dry-run --include=/{,'company*/'{,unique_folder1/{,'**'}}} --exclude='*'
    

    【讨论】:

    • 感谢@yonran,如下所示 - “包含列表”太大了。这就是将列表放在文件中的原因(请参阅下面的已接受答案)。并感谢“bash 的大括号扩展” - 需要尝试一下。
    • 这个答案是有效的,但是,如果我们使用 bash 功能,那么我们就会进入一个灰色区域 :) 在这种情况下,值得注意的是,一个简单的 shopt -s globstar; rsync -avn --relative /sourcepath/./**/a destpath 就可以了。
    猜你喜欢
    • 2019-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-28
    • 2021-06-04
    • 2017-08-14
    相关资源
    最近更新 更多