我正在尝试创建一个目录,该目录将仅容纳从LaTeX编译的所有PDF。我喜欢将每个项目都放在一个单独的文件夹中,所有项目都放在一个名为LaTeX的大文件夹中。因此,我尝试运行:

rsync -avn *.pdf ~/LaTeX/ ~/Output/


,它应该在~/LaTeX/中找到所有pdf,并将它们传输到输出文件夹。这行不通。它告诉我找不到与“ *.pdf”匹配的内容。如果我不使用此过滤器,该命令将列出LaTeX下所有项目文件夹中的所有文件。因此,这是* .pdf过滤器的问题。我尝试用主目录的完整路径替换~/,但这没有任何效果。

我正在使用zsh。我尝试在bash中执行相同的操作,甚至使用列出了每个子目录中每个文件的过滤器...这里发生了什么?

为什么rsync无法理解我的仅pdf过滤器? />

好。所以更新:不,我正在尝试

rsync -avn --include="*/" --include="*.pdf" LaTeX/ Output/


这给了我整个文件列表。我猜是因为所有内容都与第一个模式匹配...

评论

恩,你似乎是对的...我想我的答案(使用zsh的**模式)应该可以。

可能的重复项谁能告诉我为什么rsync无法从源子文件夹中复制文件?

#1 楼

TL,DR:

rsync -am --include='*.pdf' --include='*/' --exclude='*' ~/LaTeX/ ~/Output/



Rsync将源复制到目标。如果将*.pdf作为源传递,则Shell会将其扩展为当前目录中扩展名为.pdf的文件列表。不会进行递归遍历,因为您没有将任何目录作为源传递。阅读本手册时,Rsync的过滤器规则似乎令人生畏,但是您可以用一些简单的规则来构造许多示例。



包含和排除的内容:


按名称或位置排除文件很容易:rsync -a ~/LaTeX/ ~/Output/.pdf(相对于源参数,例如,不包括--exclude=*~)。
如果只想匹配几个文件或位置,则包括它们,包括指向它们的每个目录(例如--exclude=/some/relative/location),然后用~/LaTeX/some/relative/location排除其余目录。这是因为:
如果排除目录,则排除目录下的所有内容。排除的文件将不会被考虑。
如果包含目录,则不会自动包含其内容。在最新版本中,--include=*/会执行此操作。
对于每个文件,将应用第一个匹配规则(并且包括所有未匹配的规则)。 br />

如果模式不包含--exclude='*',则适用于文件名sans目录。
如果模式以--include='directory/***'结尾,则仅适用于目录。
如果模式以/开头,则它将应用于作为参数传递给/的目录的整个路径。 /匹配任何路径子字符串。


如果源参数以rsync结尾,则会复制其内容(*为每个/创建**)。否则,目录本身将被复制(/创建rsync -r a/ b)。


因此,这里我们需要包括b/foo,包括包含它们的目录,并排除其他所有内容。
rsync -a --include='*.pdf' --include='*/' --exclude='*' ~/LaTeX/ ~/Output/


请注意,这会复制所有目录,即使是不包含匹配文件的目录或包含一个目录的子目录。使用a/foo选项可以避免这种情况(这不是通用解决方案,因为即使显式匹配,您也无法复制目录,但这是很少的要求。)

评论


与我的解决方案(使用zsh的**模式)相比,这将在目标目录中重新创建目录结构。我不确定这是否是OP想要的...

– Marcel Stimberg
2010-09-29 12:08

我只想包含一个目录,并排除/etc/lsyncd/lsyncd.conf.lua文件中所有目录的其余部分。有什么想法吗?

–达达·米特什(Dhaduk Mitesh)
19年5月20日在7:01

@DhadukMitesh我对lsyncd不熟悉。您应该将其作为一个新问题提出。

–吉尔斯'所以-不再是邪恶的'
19年5月20日在7:43

@Michael我无法重现此内容。我只是在本地目录之间使用rsync 3.1.1和rsync 3.1.3进行了尝试,并且只列出了目的地(及其目录)上丢失或不同的行文件。

–吉尔斯'所以-不再是邪恶的'
20/09/17 '16:42

#2 楼

rsync -av --include="*/" --include="*.pdf" --exclude="*" ~/Latex/ ~/Output/ --dry-run


默认值是包括所有内容,因此在包括要传输的文件之后,您必须显式排除所有内容。
删除--dry-run以实际传输文件。
/>
如果您以:

--exclude '*' --include '*.pdf'


开始,那么贪婪的匹配将排除一切。 :

--include '*.pdf' --exclude '*' 


然后,仅顶层文件夹中的pdf文件将被传输。它不会跟随任何目录,因为这些目录被'*'排除。

评论


自2014年3月17日起,这是最佳答案,因为它可以准确解决原始海报问题。请投票!如果添加--prune-empty-dirs(或快捷方式-m),则您甚至可以在目标位置节省许多空目录,当然,您当然希望它们作为提醒或结构蓝图。

– porg
2014年3月17日23:38

最佳答案,--include =“ * /”是关键。

– Martin Konicek
2015年8月5日,11:46

#3 楼

如果您使用*.pdf之类的模式,则外壳程序会“扩展”该模式,即,它将用当前目录中的所有匹配项替换该模式。您正在运行的命令(在本例中为rsync)没有意识到您尝试使用模式这一事实。

在使用zsh时,有一个简单的解决方案:用于递归匹配文件夹。试试这个:

rsync -avn ~/LaTeX/**/*.pdf ~/Output/


评论


那会不会从当前目录中的某处复制所有pdf,并将所有内容从〜/ LaTeX /复制到〜/ Output?

– SamB
2010-09-16 18:35

我猜你的意思是rsync -avn〜/ LaTeX / ** / *。pdf〜/ Output,但是--include的解决方案无论如何都是可扩展的。

–亚当·伯特克(Adam Byrtek)
2010-09-16 18:58



抱歉,更正了我匆忙键入的命令...我同意include命令(在SamB的版本中)更好,尽管它对于rsync更为复杂和特定,而**在其他情况下也可能会派上用场。

– Marcel Stimberg
2010-09-16 19:10

Bash 4也采用了相同的功能。哦,这里您不需要rsync,cp可以。在某些系统上,如果文件很多,则有助于执行cd〜/ Latex && cp -p ** / *。pdf〜/ Output来避免出现“命令行太长”错误。

–吉尔斯'所以-不再是邪恶的'
2010-09-29 17:34

请注意,包含和排除过滤器中使用的rsync模式也具有执行相同功能的**。您可以通过将其他shell引号引起来来将*转义。

–丹·普里兹(Dan Pritts)
2015年2月4日在16:28



#4 楼

您可以使用find和中间文件列表(files_to_copy)解决您的问题。确保您位于主目录中,然后:

find LaTeX/ -type f -a -iname "*.pdf" > files_to_copy && rsync -avn --files-from=files_to_copy ~/ ~/Output/ && rm files_to_copy

经过Bash测试。

评论


我认为find是最可靠的解决方案,但我会选择使用finds -exec选项或使用xargs。类似于:找到LaTeX / -type f -iname“ * .pdf” -print0 | xargs -0 -i rsync -avn {}输出/

–史蒂文D
2010-09-27 17:09



是的...我建议也找到...虽然我认为rsync必须能够做到这一点。

– Gabe。
2010-09-28 19:49

这也是解决难题的一个很好的解决方案:大概我可以使用它来排除文档类是独立文件或没有同名.tex文件的文件,因为这些文件将包含在某些文档中。 ..

– Seamus
2010-09-29 12:41

rsync选项--files-from接受从stdin读取。找到LaTeX / -type f -a -iname“ * .pdf” | rsync -avn --files-from =-〜/〜/ Output /

– Juan Calero
2012-09-20 16:15



#5 楼

从联机帮助页的“包含/排除模式规则”部分判断,执行此操作的方法是

rsync -avn --include="*/" --include="*.pdf" ~/Latex/ ~/Output/


与kbrd答案之间的关键区别是--include="*/"标志,它告诉rsync继续并复制找到的任何目录,无论它们的名称如何。这是必须的,因为除非指示rsync复制该子目录,否则rsync不会递归到该子目录中。

此外,请注意引号会阻止Shell尝试将模式扩展为相对于当前目录,并执行以下操作之一:


成功并弄乱您的过滤器(不太可能出现在这样的标记中间,尽管您真的不知道何时有人会创建一个名为--include=foo.pdf的文件...)

评论


因此,这将仅复制PDF和目录结构,而kbrd将复制文件,但忽略结构?

– Seamus
2010-09-17 9:29

嗯我想这实际上似乎仍然可以尝试复制所有内容,因为那是没有过滤器的结果,因此在其中包含多余的内容不会改变任何内容。如果你明白我的意思...

– Seamus
2010-09-17 9:33

您需要在--include =“ *。pdf”之后加上--exclude =“ *”,否则将转移所有内容。

– jmanning2k
2010-09-28 20:25



@ jmanning2k:啊。很高兴知道!

– SamB
2010-09-29 21:18

#6 楼

这是我的首选解决方案:

find source_dir -iname '*.jpg' -print0 |  rsync -0 -v --files-from=- . destination_dir/


find的包含/排除规则相比,rsync命令更容易理解:-)

如果您只想复制pdf文件,只需将.jpg更改为.pdf

#7 楼

怎么样:

rsync -avn --include="*.pdf" ~/Latex/ ~/Output/


评论


不,man rsync将过滤器放在选项之后和源/目标之前。我尝试了这个,但是没有用

– Seamus
2010-09-16的16:06

您可以按照自己的方式在当前文件夹中找到.pdf文件,但不能以递归方式找到。 (该选项用于存档,除其他外,它使复制递归。

– Seamus
2010-09-16的16:07

糟糕,我的糟糕。我更新了答案。

–kbyrd
2010-09-16 16:43

+1太接近了,为我提供了有关如何在手册页中找到相关资料的线索。 (希望我什至没错。:-)

– SamB
2010-09-16 19:04

#8 楼

这是一些无需使用find即可工作的东西。与已经发布的答案的区别在于过滤规则的顺序。 rsync命令中的过滤器规则与iptable规则非常相似,文件匹配的第一个规则是所使用的规则。在手册页中:


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


,因此,您需要以下命令:

rsync -avn --include="**.pdf" --exclude="*" ~/LaTeX/ ~/Output/


请注意“ **。pdf”模式。根据手册页:


如果模式包含/(不计入结尾的/)或“ **”,则它将与完整路径名匹配,包括任何前导目录。如果
模式不包含/或“ **”,则仅与文件名的最后部分匹配。 (请记住,该算法是递归应用的,因此“完整文件名”实际上可以是从开始目录开始向下的路径的任何部分。
在目录树中递归地工作,仅选择pdf。

评论


您如何测试?根据我对文档的理解和实验验证,您的命令应仅在顶层目录中复制* .pdf(而不是〜/ LaTeX / foo / bar.pdf)。

–吉尔斯'所以-不再是邪恶的'
2010-09-28 19:25



@吉尔斯·克鲁德你是对的。我发誓我测试了一下,它确实起作用了,但是我似乎无法重新创建它。现在,我实际上已经阅读了引用的手册页,这很有意义,这是行不通的。叽。

–史蒂文D
2010-09-28 20:10

好吧,我找出了我的测试错误的地方。我的“小测试”位于具有我自己的.tex和.pdf文件的目录上。然后,我创建了一个“ test”子目录,并在该子目录中创建了一个test.pdf和test.tex。但是,我没有注意到我的顶层目录中有一个test.pdf,这可能是因为我做了一些快速的LaTeX实验。

–史蒂文D
2010-09-28 20:14

我仍然不了解**。举个例子会很好。 ;)

– Buhtz
17-10-6在9:59

#9 楼

在更新@Giles的答案时,请考虑必须使用当前版本(> = 3.xx)更改include和exclude命令的顺序,以便在排除选项之前具有包含选项,以便构建正确的文件列表。我个人的最佳实践也是通常先放置“包括所有子目录”指令,然后再放置文件模式:
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表示)时,每个路径的每个subdir组件都是从左到右访问的,每个目录在它的内容。这样,将包含/排除模式以递归方式应用于文件系统树(传输内部的树)中每个节点的路径名。排除模式会在rsync找到要发送的文件时使目录遍历阶段短路。


例如,要包含“ / foo / bar / baz”,则目录“ / foo”和“ / foo / bar”一定不能排除。排除其中一个父目录会阻止对其内容的检查,从而将rsync的递归切断到这些路径中,并使“ / foo / bar / baz”的include无效(因为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).


#10 楼

要从源目录内部生成仅包含标题(../include)的目录,请执行以下操作: