使用正则表达式进行rsync仅包含一些文件


11

我试图运行rsync以根据文件名模式(不区分大小写)沿路径递归复制一些文件。这是我运行rsync所做的:

$ rsync -avvz --include ='*/' --include='.*[Nn][Aa][Mm][E].*' --exclude='*' ./a/ ./b/

什么都没有复制,调试输出显示:

[sender] hiding file 1Name.txt because of pattern *
[sender] hiding file 1.txt because of pattern *
[sender] hiding file 2.txt because of pattern *
[sender] hiding file Name1.txt because of pattern *
[sender] hiding directory test1 because of pattern *
[sender] hiding file NaMe.txt because of pattern *

我尝试使用: --include='*[Nn][Aa][Mm][E]*'和其他组合,但仍然没有成功。

关于如何使用正则表达式包含一些文件的任何想法?


4
为什么要使用--exclude='*'

2
因此它会排除不包括在内的所有内容。

'由于模式'隐藏文件1Name.txt,这表明:-“ --exclude规则是否需要在命令中?” 或者,如果要排除某些文件,为什么要使用“ ”。
Akshay Patil

Answers:


5

rsync不讲正则表达式。您可以注册find和grep,尽管它有点奥秘。查找目标文件:

find a/ |
grep -i 'name'

但是它们都以“ a /”作为前缀-这很有意义,但我们最终要得到的是rsync可接受的包含模式列表,并且因为“ a /”前缀不适用于rsync,所以我将其切掉:

find . |
grep -i 'name' |
cut -d / -f 2-

仍然存在问题-我们仍然会丢失子目录中的文件,因为rsync不会在排除列表中搜索目录。我将使用awk将任何匹配文件的子目录添加到包含模式列表中:

find a/ |
grep -i 'name' |
cut -d / -f 2- |
awk -F/ '{print; while(/\//) {sub("/[^/]*$", ""); print}}'

剩下的就是将列表发送到rsync-我们可以使用参数--include-from =-提供标准输入上rsync的模式列表。因此,总共:

find a/ |
grep -i 'name' |
cut -d / -f 2- |
awk -F/ '{print; while(/\//) {sub("/[^/]*$", ""); print}}' |
rsync -avvz --include-from=- --exclude='*' ./a/ ./b/

注意,源目录“ a”是通过两个不同的路径引用的:“ a /”和“ ./a/”。这是微妙但重要的。为了使事情更加一致,我将作最后的更改,并始终将源目录称为“ ./a/”。但是,这意味着cut命令必须更改,因为find结果的前面将有一个额外的“ ./”:

find ./a/ |
grep -i 'name' |
cut -d / -f 3- |
awk -F/ '{print; while(/\//) {sub("/[^/]*$", ""); print}}' |
rsync -avvz --include-from=- --exclude='*' ./a/ ./b/

试图运行它,遇到cut命令的问题。似乎-t是一个有效的开关。

编辑:我的意思是-t不是有效的开关

抱歉,应该是-d。我开始使用sed,然后更改为剪切,因为我认为它更清晰,但是却忘记了编辑命令:S

跟进:尝试编辑脚本以接受参数($ 1 = path_to_search,$ 2作为egrep的模式),因为我匹配文件名+扩展名的混合。该部分工作正常,我得到了预期的列表,但是rsync无法复制。似乎仅适用于单名称字符目录,如示例(a)所示:我的猜测是必须修改cut命令以基于父目录或源目录剪切字符吗?金达(Kinda)不知道该怎么做:
2013年

是的,您说得很对。它可以在任何长度的目录名称上工作,但是一旦您引用当前目录之外的目录,它就会失败(因为在前缀部分会有不同数量的斜杠)。要解决此问题,可能最容易使用sed而不是cut,例如:sed "s#^$1/*##" buuuut会在包含#的路径上中断。为了解决这个问题,我们必须引用传入的目录名称:prefix=$(echo "$1" | sed 's#/#\\/#g')然后sed "s/^$prefix\\/*//" bash引用的子例程有点噩梦;)
sqweek 2013年

7

我建议使用rsync的filter选项。对于您的示例,只需键入:

rsync -vam -f'+ *[Nn][Aa][Mm][E]*' -f'+ */' -f'- *' a b

第一个过滤规则告诉rsync要包括哪些模式。需要第二条规则来告诉rsync检查遍历的所有目录。为了防止包含空目录,它们由-m选项明确排除。最后一个过滤器规则告诉rsync处理到目前为止仍不匹配的所有剩余模式。


甜。这也很好。我在b内部获得了文件夹a,通过使用a / b /作为源和目标对其进行了修复。谢谢!
user1957413

使用-f'+ * [Nn] [Aa] [Mm] [E] **'(末尾加两个星号)可包含具有特定名称的所有目录的内容。
恐惧症患者

2

如果使用ZSH,则可以使用(#i)标志关闭区分大小写。例:

$ touch NAME
$ ls (#i)*name*
NAME

ZSH还支持排除项,排除项的指定方式与常规路径一样,但它们的开头是〜

$ touch aa ab ac
$ ls *~*c
aa ab

您可以链接排除项:

$ ls *~*c~*b
aa

最后,您可以指定要返回的文件类型(目录,文件等)。通过(/)表示目录,使用(。)表示文件。

$ touch file
$ mkdir dir
$ ls *(.)
file

基于所有这些,我将执行以下命令:

rsync -avvz *(/) (#i)*name* ./a/ ./b/

(我认为这些选择器不需要排除)


1

上面@sqweek的答案很棒,尽管我怀疑他的awk脚本中有一个用于生成父目录的错误,因为它给了我例如:

$ echo a/b/c/d | awk -F/ '{print; while(/\//) {sub("/[^/]*", ""); print}}'
a/b/c/d
a/c/d
a/d
a

我可以改为使用以下方式修复它gensub

$ echo a/b/c/d | awk -F/ '{print; while(/\//) { $0=gensub("(.*)/[^/]*", "\\1", "g"); print}}'
a/b/c/d
a/b/c
a/b
a

因此,随着一awk点点改变,他的完整解决方案将是:

find ./a/ |
grep -i 'name' |
cut -d / -f 3- |
awk -F/ '{print; while(/\//) { $0=gensub("(.*)/[^/]*", "\\1", "g"); print}}' |
rsync -avvz --include-from=- --exclude='*' ./a/ ./b/

谢谢。使用将正则表达式锚定到行尾(sub("/[^/]*$"))的等效修复程序编辑了我的答案。
sqweek

0

因为我是最有经验的语言,所以尝试过使用C#脚本。我能够创建要包括的文件列表,但是有人rsync仍然告诉我加息。它创建文件夹,但忽略文件。这是我得到的。

首先是目录的内容:

~/mono$ ls -l
total 24
drwxr-xr-x 5 me me 4096 Jan 15 00:36 a
drwxr-xr-x 2 me me 4096 Jan 15 00:36 b
drwxr-xr-x 3 me me 4096 Jan 14 00:31 bin
-rw-r--r-- 1 me me 3566 Jan 15 00:31 test.cs
-rwxr-xr-x 1 me me 4096 Jan 15 00:31 test.exe
-rwxr--r-- 1 me me  114 Jan 14 22:40 test.sh

然后是C#脚本的输出:

~/mono$ mono test.exe

/a/myfile/myfileseries.pdf
/a/myfile2/testfile.pdf

和调试输出:

~/mono$ mono test.exe | rsync -avvvz --include='*/' --include-from=- --exclude='*' ./a/ ./b/
[client] add_rule(+ */)
[client] parse_filter_file(-,20,3)
[client] add_rule(+ /a/myfile/myfileseries.pdf)
[client] add_rule(+ /a/myfile2/testfile.pdf)
[client] add_rule(- *)
sending incremental file list
[sender] make_file(.,*,0)
[sender] hiding file 1Name.txt because of pattern *
[sender] showing directory myfile2 because of pattern */
[sender] make_file(myfile2,*,2)
[sender] hiding file 1.txt because of pattern *
[sender] hiding file 2.txt because of pattern *
[sender] hiding file Name1.txt because of pattern *
[sender] showing directory test1 because of pattern */
[sender] make_file(test1,*,2)
[sender] hiding file NaMe.txt because of pattern *
[sender] showing directory myfile because of pattern */
[sender] make_file(myfile,*,2)
send_file_list done
send_files starting
[sender] hiding file myfile/myfileseries.pdf because of pattern *
[sender] hiding file myfile2/testfile.pdf because of pattern *
[sender] hiding file test1/test.txt because of pattern *

0

[编辑]这仅在本地有效。对于远程路径,必须首先创建目录结构。

比接受的答案更简单;使用--file-from,它将自动包含父目录,并使用%P打印文件路径

find /tmp/source -wholename '*[Nn][Aa][Mm][E]*' -printf '%P\n' | rsync -vzrm --exclude='*/' --files-from=- /tmp/source/ /tmp/target/

因此,您只需使用findrsync

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.