Skip to content

Commit

Permalink
doc: improve juicefs sync include and exclude pattern rules docum…
Browse files Browse the repository at this point in the history
…ent (#4438)
  • Loading branch information
zhijian-pro authored May 6, 2024
1 parent 3ad9094 commit 55ab091
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 22 deletions.
115 changes: 93 additions & 22 deletions docs/zh_cn/guide/sync.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,36 +158,107 @@ juicefs mount -d redis://10.10.0.8:6379/1 /mnt/jfs
juicefs sync --force-update s3://ABCDEFG:[email protected]/movies/ /mnt/jfs/movies/
```

## 模式匹配 {#pattern-matching}
### 过滤 {#filter-matching}

类似 rsync,你可以用 `--exclude``--include` 来过滤需要同步的文件,并通过多个规则的组合实现任意集合的同步,规则如下:
你可以通过参数 `--exclude``--include` 来提供多个字符串模式来过滤将要同步的路径,`--exclude` 表示不同步匹配上的路径,`--include` 表示同步匹配上的路径。当不提供任何规则时,默认会同步所有发现的路径。
当有多个过滤模式时,它会按照提供的顺序进行匹配尝试,并依照第一个匹配上的模式来决定是否同步某个路径,所有模式都不能匹配上时则要同步该路径。通过多个规则的按序组合实现任意集合的同步。

-`/` 结尾的模式会仅匹配目录,否则会匹配文件、链接或设备;
- 包含 `*``?``[` 字符时会以通配符模式匹配,否则按照常规字符串匹配;
- `*` 匹配任意非空路径组件,在 `/` 处停止匹配;
- `?` 匹配除 `/` 外的任意字符;
- `[` 匹配一组字符集合,例如 `[a-z]``[[:alpha:]]`
- 在通配符模式中,反斜杠可以用来转义通配符,但在没有通配符的情况下,会按字面意思匹配;
- 在使用包含/排除规则时,位置在前的选项优先级更高。`--include` 应该排在前面,如果先设置 `--exclude '*'` 排除了所有文件,那么后面的 `--include 'xxx'` 包含规则就不会生效。
#### 匹配规则

例如,同步所有文件,但排除隐藏文件(以 `.` 为开头命名均被视为隐藏文件):
匹配规则指的是给定一个路径与一个模式,如何确定该路径能否匹配上该模式。
模式可以包含一下特殊字符(类似 shell 通配符):

```shell
# 排除隐藏文件
juicefs sync --exclude '.*' /tmp/dir/ s3://ABCDEFG:[email protected]/
```
+ 单个`*`匹配任意路径元素,但在遇到 `/` 终止匹配。
+ `**` 匹配任意路径元素,包括 `/`
+ `?`匹配任意非 `/` 的单个字符。
+ `[`表示字符类匹配,例如`[a-z]` 匹配任意小写字母。`[^abc]` 匹配`a` `b` `c` 外的任意字符
一个模式需要跟路径的包括最底层在内的若干层级进行完整匹配,比如 `foo` 匹配 `foo``xx/foo`,但不匹配 `foo1``2foo``foo/xx`
当匹配模式以 `/` 结尾,将只匹配目录,而不匹配普通文件。
如果匹配模式以 `/` 开头,则表示匹配完整路径(路径不需要以 `/` 开头),因此 `/foo` 匹配的是传输中根目录的 `foo` 文件。

重复该选项匹配更多规则,例如,排除所有隐藏文件、`pic/` 目录 和 `4.png`
#### 过滤模式

```shell
juicefs sync --exclude '.*' --exclude 'pic/' --exclude '4.png' /tmp/dir/ s3://ABCDEFG:[email protected]
```
过滤模式是指如何根据多个过滤模式来决定是否同步某个路径。`sync` 命令支持一次性和逐级两种过滤模式。默认情况下,`sync` 命令使用逐层过滤模式,可以通过 `--match-full-path` 参数来使用一次性过滤模式。

使用 `--include` 选项设置要包含的目录或文件,例如,只同步 `pic/``4.png` 两个文件,其他文件都排除:
##### 一次过滤模式

```shell
juicefs sync --include 'pic/' --include '4.png' --exclude '*' /tmp/dir/ s3://ABCDEFG:[email protected]
```
![一次性过滤示例图](../images/sync-single-layer-filtration.svg)

一次性过滤是指针对待匹配的对象,直接将其全路径与多个模式进行依次匹配。

例如现有对象 `a1/b1/c1.txt``include/exclude` 规则 `--include a*.txt --inlude c1.txt --exclude c*.txt`。直接将 `a1/b1/c1.txt` 这个字符串与 `--include a*.txt``--inlude c1.txt``--exclude c*.txt` 三个模式进行依次匹配。
具体步骤:

1. `a1/b1/c1.txt``--include a*.txt` 尝试匹配,结果是未匹配
2. 尝试下一个规则 `a1/b1/c1.txt``--inlude c1.txt` 尝试匹配,此时根据匹配规则,将会匹配成功。直接返回 `a1/b1/c1.txt` 的最终匹配结果为“同步”。

后续的 `--exclude c*.txt` 虽然根据后缀匹配规则也能匹配上,但是根据 `include/exclude` 参数的顺序性规则,一旦匹配上一个某个模式得到单层匹配的结果后,后续的模式将不再尝试匹配。所以匹配结果是`--inlude c1.txt` 模式的行为——“同步”。

以下是一些 `exclude/include` 规则一次性过滤模式的例子:

+ `--exclude *.o` 将排除所有文件名能匹配 `*.o` 的文件。
+ `--exclude /foo**` 将排除传输中根目录名为 `foo` 的文件或目录。
+ `--exclude **foo/**` 将排除所有以 `foo` 结尾的目录。
+ `--exclude /foo/*/bar` 将排除传输中根目录下 `foo` 目录再向下两层的 `bar` 文件。
+ `--exclude /foo/**/bar` 将排除传输中根目录下 `foo` 目录再向下递归任意层次后名为 `bar` 的文件。( `**` 匹配任意多个层次的目录)
+ 同时使用 `--include */ --include *.c --exclude *` 将只包含所有目录和 C 源码文件,除此之外的所有文件和目录都被排除。
+ 同时使用 `--include foo/bar.c --exclude *` 将只包含 `foo` 目录和 `foo/bar.c`

一次性过滤模式是一种理解与使用都较为简单的模式,一般情况下推荐大家使用这种模式。

##### 逐层过滤模式

![逐层过滤示例图](../images/sync-hierarchical-filtration.svg)

逐层过滤的核心是先将待匹配的对象路径按照路径层级逐层增加的子路径元素依次组成序列,比如原始路径为 `a1/b1/c1.txt` 的对象层级过滤的序列就是 `a1`,`a1/b1`,`a1/b1/c1.txt`
然后将这这个序列中的每个元素都当成一次性过滤中的原始路径,依次执行“一次性过滤”。“一次性过滤”中如过匹配上了某个模式,如果该模式是 exclude 模式,则直接返回“排除”行为作为整个层级匹配原始对象的结果,
如果该模式是 include 模式,则跳过本层级的后续待匹配的模式直接进入下一层级的过滤。
如过某层的所有规则都未匹配,则进入下一层级过滤,如果所有层级都执行完毕则返回默认的行为——“同步”。

例如现有对象 `a1/b1/c1.txt``--include a*.txt`, `--inlude c1.txt`, `--exclude c*.txt`,可以结合逐层过滤图片分析步骤,在这个例子中子路径序列就分别是 `a1`,`a1/b1`,`a1/b1/c1.txt`
该例子的逐层过滤具体步骤:

1. 第一层级 `a1`,一次性过滤的路径是 `a1`,模式序列是 `--include a*.txt`, `--inlude c1.txt`, `--exclude c*.txt`,根据匹配规则,结果将会是本层内全部未匹配。继续下一层级。
2. 第二层级 `a1/b1`,一次性过滤的路径是 `a1/b1`,模式序列是 `--include a*.txt`, `--inlude c1.txt`, `--exclude c*.txt`,根据匹配规则,结果将会是本层内全部未匹配。继续下一层级。
3. 第三层级的一次性过滤,一次性过滤的路径是 `a1/b1/c1.txt`,模式序列是 `--include a*.txt`, `--inlude c1.txt`, `--exclude c*.txt`,根据匹配规则,结果将会是匹配上 `--inlude c1.txt` 模式。
该模式的行为是“同步”,逐层过滤中,逐层过滤结果如果是“同步”则将直接进入下一层过滤。
4. 没有下一层级了,所有过滤层级都已经执行完毕,所以返回默认的行为——“同步”。

上面的例子是到层级最后一层才匹配成功,除此之外还有两种情况:

1. 匹配未到最后一层,在某层提前匹配成功,此时如果是 exclude 模式则直接返回“排除”作为整个层级过滤的最终结果,如果是 include 模式则直接进入下一层过滤。
2. 所有过滤层级都已经执行完毕,但都未匹配上,此时也将会返回默认的行为作为最终结果——“同步”。

一句话讲,层级过滤就是路径层级由高到低的一次性过滤的按序执行,层级过滤的每层过滤只有两种结果,要么直接得到“排除”最终结果,要么进入下一层过滤,得到“同步”结果的唯一方式是执行完所有过滤层级。

以下是一些 exclude/include 规则层级过滤模式的例子:

+ `--exclude *.o`将排除所有文件名能匹配"*.o"的文件。
+ `--exclude /foo`将排除传输中根目录名为"foo"的文件或目录。
+ `--exclude foo/`将排除所有名为"foo"的目录。
+ `--exclude /foo/*/bar` 将排除传输中根目录下"foo"目录再向下两层的"bar"文件。
+ `--exclude /foo/**/bar` 将排除传输中根目录下"foo"目录再向下递归任意层次后名为"bar"的文件。("**"匹配任意多个层次的目录)
+ 同时使用`--include */ --include *.c --exclude *` 将只包含所有目录和 C 源码文件,除此之外的所有文件和目录都被排除。
+ 同时使用 `--include foo/ --include foo/bar.c --exclude *` 将只包含"foo"目录和"foo/bar.c"。("foo"目录必须显式包含,否则将被排除规则`--exclude *`排除掉)
+ 对于 `dir_name/***` 来说,它将匹配 dir_name 下的所有层次的文件。注意,每个子路径元素会自顶向下逐层,被访问因此 `include/exclude` 匹配模式会对每个子路径元素的全路径名进行递归 (例如,要包含 `/foo/bar/baz`,则`/foo``/foo/bar`必须不能被排除)。实际上,排除匹配模式在发现有文件要传输时,此文件所在目录层次的排除遍历会被短路。如果排除了某个父目录,则更深层次的 include 模式匹配将无效,这在使用尾随`*`时尤为重要。例如,下面的例子不会正常工作:

```
--include='/some/path/this-file-will-not-be-found'
--include='/file-is-included'
--exclude='*'
```

由于父目录 `some` 被规则`*`所排除,所以会失败。一种解决方式是请求包含层次结构中的所有目录,只需使用一个规则`--include */`(需放在`--include*`规则的前面) 即可,另一解决方式是为所有需要被访问的父目录增加特定包含规则。例如,下面的规则可以正常工作:

```
--include /some/
--include /some/path/
--include /some/path/this-file-is-found
--include /file-also-included
--exclude *
```

逐层过滤的行为无论是理解还是使用都较为复杂,但是基本兼容 rsync 的 `include/exclude` 参数,所以一般推荐在兼容 rsync 行为的场景下采用。

### 目录结构与文件权限

Expand Down
3 changes: 3 additions & 0 deletions docs/zh_cn/images/sync-hierarchical-filtration.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 55ab091

Please sign in to comment.