在对@Giles的回答进行更新时,请考虑到在当前版本(>=3.x.x)中必须更改包含和排除命令的顺序,以便在构建正确的文件列表时将包含选项放在排除选项之前。这也是我个人的最佳实践,通常先放置“包括所有子目录”的指令,然后再放置文件模式:
rsync -avh --include='*/' --include='file-pattern' --exclude='*' /sourcedir/ /targetdir/
在你的情况下,即例如:
rsync -avh --include='*/' -include='*.pdf' --exclude='*' ~/LaTeX/ ~/Output/
可以从
https://www.samba.org/ftp/rsync/rsync.html的“过滤规则”章节中进一步解释:
请注意,当使用--recursive (-r)选项时(这是-a选项隐含的),每个路径的每个子目录组件都会从左到右地被访问,每个目录都有机会在其内容之前被排除。通过这种方式,包含/排除模式会递归地应用于文件系统树中每个节点的路径名(传输内部的节点)。排除模式在rsync找到要发送的文件时会终止目录遍历阶段。
例如,要包含“/foo/bar/baz”,必须不排除“/foo”和“/foo/bar”目录。如果其中一个父目录被排除,则会阻止其内容的检查,切断rsync对这些路径的递归,并使得对“/foo/bar/baz”的包含变得无效(因为rsync无法在被截断的目录层次结构的部分中匹配到它从未看到的东西)。
在使用以“*”结尾的规则时,路径排除的概念尤为重要。例如,以下方法行不通:
+ /some/path/this-file-will-not-be-found
+ /file-is-included
- *
这个失败是因为父目录"some"被"*"规则排除了,所以rsync从不访问"some"或"some/path"目录中的任何文件。一个解决办法是通过使用单个规则"+ */"(将其放在"- *"规则之前的某个位置)来要求包括层次结构中的所有目录,并可能使用--prune-empty-dirs选项。另一种解决办法是为需要访问的所有父目录添加特定的包含规则。例如,以下一组规则可以正常工作:
+ /some/
+ /some/path/
+ /some/path/this-file-is-found
+ /file-also-included
- *
以下是一些排除/包含匹配的示例:
"- *.o" would exclude all names matching *.o
"- /foo" would exclude a file (or directory) named foo in the transfer-root directory
"- foo/" would exclude any directory named foo
"- /foo/*/bar" would exclude any file named bar which is at two levels below a directory named foo in the transfer-root directory
"- /foo/**/bar" would exclude any file named bar two or more levels below a directory named foo in the transfer-root directory
The combination of "+ */", "+ *.c", and "- *" would include all directories and C source files but nothing else (see also the --prune-empty-dirs option)
The combination of "+ foo/", "+ foo/bar.c", and "- *" would include only the foo directory and foo/bar.c (the foo directory must be explicitly included or it would be excluded by the "*")
在“+”或“-”后面可以接受以下修饰符:
A / specifies that the include/exclude rule should be matched against the absolute pathname of the current item. For example, "-/ /etc/passwd" would exclude the passwd file any time the transfer was sending files from the "/etc" directory, and "-/ subdir/foo" would always exclude "foo" when it is in a dir named "subdir", even if "foo" is at the root of the current transfer.
A ! specifies that the include/exclude should take effect if the pattern fails to match. For instance, "-! */" would exclude all non-directories.
A C is used to indicate that all the global CVS-exclude rules should be inserted as excludes in place of the "-C". No arg should follow.
An s is used to indicate that the rule applies to the sending side. When a rule affects the sending side, it prevents files from being transferred. The default is for a rule to affect both sides unless --delete-excluded was specified, in which case default rules become sender-side only. See also the hide (H) and show (S) rules, which are an alternate way to specify sending-side includes/excludes.
An r is used to indicate that the rule applies to the receiving side. When a rule affects the receiving side, it prevents files from being deleted. See the s modifier for more info. See also the protect (P) and risk (R) rules, which are an alternate way to specify receiver-side includes/excludes.
A p indicates that a rule is perishable, meaning that it is ignored in directories that are being deleted. For instance, the -C option's default rules that exclude things like "CVS" and "*.o" are marked as perishable, and will not prevent a directory that was removed on the source from being deleted on the destination.
An x indicates that a rule affects xattr names in xattr copy/delete operations (and is thus ignored when matching file/dir names). If no xattr-matching rules are specified, a default xattr filtering rule is used (see the --xattrs option).
**
模式)应该可以解决问题。 - Marcel Stimberg