rsync使用include选项仅复制某些类型的文件


110

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

从= $ 1
至= $ 2

rsync -zarv --include =“ *。sh” $ from $ to

4
虽然不是严格说来相关,但我建议引用$ from / $ to。如果位置参数1/2包含空格,则不这样做可能会给您带来意想不到的结果。
Kjetil Joergensen 2012年

您了解为什么命令不起作用吗?
查理·帕克

@CharlieParker:您必须使用rsync,这可以通过外壳内部实现吗?

如果我有只希望发送一种类型的文件的递归目录,那么这个问题及其答案还缺少的是如何编写命令。看来它只对目标目录
Charlie Parker

Answers:


200

我认为--include过去是用来包含文件的子集,否则会被排除--exclude,而不仅仅是包括那些文件。换句话说:您必须考虑包含含义,不要排除

请尝试:

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

对于rsync 3.0.6或更高版本,需要按以下方式修改顺序(请参见注释):

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

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

因此,如果只希望* .sh文件,则必须排除所有文件--exclude="*",包括所有目录,--include="*/"并包括所有* .sh文件--include="*.sh"

您可以在手册页的“包括/排除模式规则”部分中找到一些很好的示例。


10
虽然它会为您提供所有子目录,但是如果您要rsync的子目录中有任何.sh文件,您也可能会使用--include =“ * /”。
Kjetil Joergensen

50
我在很早以前从macports获得的rsync版本3.0.7上尝试了此方法,但不适用于这种包含/排除的顺序。这是我结束了,对我的工作(适用于OP) rsync -zarv --include="*/" --include="*.sh" --exclude="*" "$from" "$to"
Bijou Trouvaille

3
我尝试了rsync 3.0.9,但没有用。珠宝是正确的,排序不正确(第一--include=\*.sh--exclude=\*
TrueY

3
请注意,您始终可以单击“编辑”并建议对答案进行编辑:)
Achal Dave 2014年

2
它不工作与你的包括/ exludes的排序,但它与珠宝Trouvaille建议排序工作
约翰·史密斯可选

57

@chepner的答案将复制所有子目录,而不管其是否包含文件。如果您需要排除不包含文件但仍保留目录结构的子目录,请使用

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

1
这是我的要求:“如果您需要排除不包含文件的子目录,但仍保留目录结构”,+ 1
Juuso Ohtonen

1
我不明白您怎么知道--includes的顺序?
查理·帕克

1
如果我有递归目录,而我只想发送一种类型的文件,那么该命令将如何处理?似乎只对目标目录执行此操作。
查理·帕克

15

另外还有一个额外的功能:如果只需要在一个目录中同步文件的扩展名(没有递归),则应该使用如下结构:

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

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

编辑:

感谢gbyte.co的宝贵意见!


1
您怎么知道标志的顺序必须是什么以及它们需要包含什么?
查理·帕克

1
@CharlieParker,因为rsync 按指定的顺序使用includeexclude选项。此外,它在第一个匹配的选项处停止。因此,如果--exclude '*'在此示例中首先指定,则rsync将不执行任何操作。请参阅此人以获取更多说明。
Serge Roussak

您能告诉我每个标志在做什么吗?第一个标志-- include './' 是说在源目录路径中包含所有内容?然后下一个`--include'.ext'`在源路径中包含命名的特定文件.ext,然后exclude表示不发送其他内容--exclude '*'?那是对的吗?
查理·帕克

1
如果我有递归目录,而我只想发送一种类型的文件,那么该命令将如何处理?似乎只对目标目录执行此操作。
查理·帕克

1
谢谢你!需要--include '*.ext'而不是--include '.ext'
gbyte

13

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

构建要传输的文件/目录列表后,rsync会根据包含/排除模式列表依次检查要传输的每个名称,然后执行第一个匹配模式:如果是排除模式,则该文件为跳过 如果是包含模式,则不跳过该文件名;如果找不到匹配的模式,则不跳过文件名。

总结一下:

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

同样,以斜杠结尾的东西是匹配目录(就像find -type d这样)。

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

rsync -zarv  --prune-empty-dirs --include "*/"  --include="*.sh" --exclude="*" "$from" "$to"
  1. 不要跳过任何目录
  2. 不要跳过任何.sh文件
  3. 跳过一切
  4. (示意性地,不要跳过任何内容,但是上面的规则可以防止发生默认规则。)

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


非常感谢您解释发生了什么。现在,我将不会忘记该命令的机会更大。
MohamedEzz

3
“一旦有任何模式匹配,算法就会退出” —这是关键,而且没有一个更高评价的答案像您在此所做的那样清楚和直观地进行解释。当然,这在手册页中,如果我我已经仔细阅读了整个内容,但我还是看到了
TheDudeAbides

0

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

使用rsync文件:

my-dir/
my-file.txt

- /*

0

编写了这个方便的功能,并放入了我的bash脚本或~/.bash_aliases。使用bash在Linux上测试了本地同步并awk已安装。有用

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.