【问题标题】:rsync copy over only certain types of files using include optionrsync 使用包含选项仅复制某些类型的文件
【发布时间】:2012-06-22 02:49:34
【问题描述】:

我使用以下 bash 脚本仅复制具有特定扩展名的文件(在本例中为 *.sh),但它仍会复制所有文件。怎么了?

从=$1 到=$2 rsync -zarv --include="*.sh" $from $to

【问题讨论】:

  • 虽然严格来说不相关,但我建议引用 $from/$to。如果位置参数 1/2 包含空格,则不这样做可能会给您带来意想不到的结果。
  • 你明白为什么你的命令不能正常工作了吗?
  • @CharlieParker:你必须使用rsync吗,这可以通过shell内部实现吗?
  • 这个问题及其答案也缺少的是,如果我有递归目录,我只想发送一种类型的文件,如何制作命令。似乎它只对目标目录起作用......
  • 旁注:-r 是多余的,因为-a 意味着-r

标签: linux bash shell rsync


【解决方案1】:

@chepner 的答案将复制所有子目录,无论它是否包含文件。如果需要排除不包含文件的子目录,仍然保留目录结构,使用

rsync -zarv  --prune-empty-dirs --include "*/"  --include="*.sh" --exclude="*" "$from" "$to"

【讨论】:

  • 这是对我的要求:“如果你需要排除不包含文件的子目录并仍然保留目录结构”+1
  • 我不明白你怎么知道 --include 的顺序是什么?
  • 如果我有递归目录,我只想发送一种类型的文件,如何制作命令。它似乎只对目标目录起作用。
  • 正是我需要的。谢谢!
【解决方案2】:

编写了这个方便的函数并将其放入我的 bash 脚本或~/.bash_aliases。在安装了 bash 和 awk 的 Linux 上测试了本地同步。有效

selrsync(){
# selective rsync to sync only certain filetypes;
# based on: https://stackoverflow.com/a/11111793/588867
# Example: selrsync 'tsv,csv' ./source ./target --dry-run
types="$1"; shift; #accepts comma separated list of types. Must be the first argument.
includes=$(echo $types| awk  -F',' \
    'BEGIN{OFS=" ";}
    {
    for (i = 1; i <= NF; i++ ) { if (length($i) > 0) $i="--include=*."$i; } print
    }')
restargs="$@"

echo Command: rsync -avz --prune-empty-dirs --include="*/" $includes --exclude="*" "$restargs"
eval rsync -avz --prune-empty-dirs --include="*/" "$includes" --exclude="*" $restargs
}

优点:

当一个人想要添加更多参数(即--dry-run)时,它很方便且可扩展。

示例:

selrsync 'tsv,csv' ./source ./target --dry-run

【讨论】:

    【解决方案3】:

    还有一个补充:如果您需要通过一个目录中的扩展名同步文件(没有递归),您应该使用这样的结构:

    rsync -auzv --include './' --include '*.ext' --exclude '*' /source/dir/ /destination/dir/
    

    请注意第一个--include 中的点。 --no-r 在此构造中不起作用。

    编辑:

    感谢 gbyte.co 的宝贵意见!

    编辑:

    -uzv 标志与这个问题没有直接关系,但我将它们包括在内,因为我经常使用它们。

    【讨论】:

    • 你怎么知道标志的顺序是什么以及它们需要包含什么?
    • @CharlieParker,因为 rsync 按指定顺序使用includeexclude 选项。除此之外,它会在第一个匹配的选项处停止。所以,如果我们在这个例子中首先指定--exclude '*',rsync 将什么都不做。更多解释请见该人。
    • 你能向我解释一下每个标志在做什么吗?第一个标志-- include './' 是说在源目录路径中包含所有内容?然后下一个`--include '.ext'`在名为.ext的源路径中包含特定文件,然后排除说不要发送任何其他内容--exclude '*'?对吗?
    • 如果我有递归目录,我只想发送一种类型的文件,如何制作命令。它似乎只对目标目录起作用。
    • 谢谢!需要--include '*.ext' 而不是--include '.ext'
    【解决方案4】:

    如果有人在寻找这个…… 我只想 rsync 特定的文件和文件夹并设法用这个命令做到这一点:rsync --include-from=rsync-files

    使用 rsync 文件:

    my-dir/
    my-file.txt
    
    - /*
    

    【讨论】:

      【解决方案5】:

      这是手册页中的重要部分:

      随着要传输的文件/目录列表的建立,rsync 会依次根据包含/排除模式列表检查要传输的每个名称,并对第一个匹配的模式进行操作:如果它是排除模式,则该文件被跳过;如果它是包含模式,则不会跳过该文件名;如果没有找到匹配的模式,则不跳过文件名。

      总结一下:

      • 不匹配任何模式意味着将复制文件!
      • 一旦任何模式匹配,算法就会退出

      此外,以斜杠结尾的内容是匹配目录(如 find -type d 会)。

      让我们从上面拆开这个答案。

      rsync -zarv  --prune-empty-dirs --include "*/"  --include="*.sh" --exclude="*" "$from" "$to"
      
      1. 不要跳过任何目录
      2. 不要跳过任何.sh 文件
      3. 跳过所有内容
      4. (隐含地,不要跳过任何内容,但上面的规则会阻止默认规则发生。)

      最后,--prune-empty-directories 保留了第一条规则,不会在各处创建空目录。

      【讨论】:

      • 非常感谢您解释发生了什么。现在我不会忘记命令的机会要大得多。
      • ''一旦任何模式匹配,算法就会退出" - 这是关键,没有一个更高评价的答案能像你那样清楚和预先解释它在这里。当然,这个在手册页中的某个地方,如果我仔细阅读整个内容,我会看到的。不过,谢谢。
      • 另一个关键概念是“当使用 --recursive (-r) 选项(由 -a 隐含)时,每个路径的每个子目录组件从左到右访问,每个目录在其内容之前有机会被排除。通过这种方式,包含/排除模式递归地应用于每个节点的路径名“。
      • ''一旦任何模式匹配,算法就会退出" -- 如果这是真的,那么--include "*/" 不应该允许同步任何文件中的任何文件目录?还是匹配文件需要匹配目录模式和匹配文件模式?
      • @FlexMcMurphy - "a '*' matches any path component, but it stops at slashes."
      【解决方案6】:

      我认为--include 用于包含--exclude 以其他方式排除的文件子集,而不是仅包含这些文件。 换句话说:您必须考虑 include 的含义不排除

      试试吧:

      rsync -zarv  --include "*/" --exclude="*" --include="*.sh" "$from" "$to"
      

      对于rsync 3.0.6或更高版本,需要修改顺序如下(见cmets):

      rsync -zarv --include="*/" --include="*.sh" --exclude="*" "$from" "$to"
      

      添加-m 标志将避免在目标中创建空目录结构。在 3.1.2 版本中测试。

      所以如果我们只想要 *.sh 文件,我们必须排除所有文件 --exclude="*",包括所有目录 --include="*/" 并包括所有 *.sh 文件 --include="*.sh"

      您可以在man page

      Include/Exclude Pattern Rules 部分找到一些很好的示例

      【讨论】:

      • 虽然它会为您提供所有子目录,但如果您想要 rsync 子目录中有任何 .sh 文件,您可能也想使用 --include="*/" 。
      • 我在很久以前从 macports 获得的 rsync 版本 3.0.7 上试过这个,但它不适用于包含/排除的这种排序。这就是我最终得到的对我有用的东西(适用于 OP):rsync -zarv --include="*/" --include="*.sh" --exclude="*" "$from" "$to".
      • 我尝试使用 rsync 3.0.9,但它不起作用。 Bijou是对的,顺序不对(先--include=\*.sh--exclude=\*
      • 请注意,您始终可以单击编辑并建议对答案进行编辑:)
      • 它不适用于您对包含/排除的排序,但它适用于 Bijou Trouvaille 建议的排序
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-01-31
      • 1970-01-01
      • 1970-01-01
      • 2020-03-22
      • 2010-10-16
      • 1970-01-01
      • 2012-04-14
      相关资源
      最近更新 更多