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

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

我正在尝试运行 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]*'和其他组合,但仍然不起作用。

关于如何使用正则表达式来包含一些文件有什么想法吗?

答案1

rsync 不支持正则表达式。您可以使用 find 和 grep,尽管这有点晦涩难懂。要查找目标文件:

find a/ |
grep -i 'name'

但是它们都以“a/”为前缀 - 这是有道理的,但我们最终想要得到的是一个 rsync 可以接受的包含模式列表,而由于“a/”前缀不适用于 rsync,我将使用 cut 将其删除:

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/

答案2

我建议使用 rsync 的过滤选项。例如,只需输入:

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

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

答案3

如果您使用 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/

(我不认为有必要用这些选择器进行排除)

答案4

尝试使用 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 *

相关内容