Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
zhijian-pro committed Apr 24, 2024
1 parent 8bdb5ec commit d038314
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 24 deletions.
51 changes: 27 additions & 24 deletions docs/zh_cn/guide/sync.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ juicefs sync --force-update s3://ABCDEFG:[email protected]/
`exclude/include` 的两个要点:

1. 默认情况下,`juicefs sync` 默认是传输所有扫描到的文件的,但是 exclude 参数则允许排除符合某种模式的文件从而达到某些文件不被传输的效果。而 `include``exclude` 的含义相反则是不排除这些文件。
2. `exclude/include` 规则可以有任意多个,且先后顺序是有意义的。可以是 `--include pattern1 --exclude pattern2`,也可以是 `--exclude pattern2 --include pattern1`, 参数相同但顺序不同,两者代表意义就不同。原因是针对对单个文件,先匹配上的规则生效,一旦匹配上后续的规则就不再匹配了,即如果先匹配上 `exclude` 规则,则该文件被跳过,如果该文件先匹配 `include` 或不能匹配任何规则,则不跳过该文件。
2. `exclude/include` 规则可以有任意多个,且先后顺序是有意义的。可以是 `--include pattern1 --exclude pattern2`,也可以是 `--exclude pattern2 --include pattern1`, 参数相同但顺序不同,两者代表意义就不同。原因是针对对单个文件,先匹配上的规则先生效,后续的规则直接就不再匹配了,即如果先匹配上 `exclude` 规则,则该文件被跳过,如果该文件先匹配 `include` 或不能匹配任何规则,则不跳过该文件。

#### 匹配规则

Expand All @@ -192,69 +192,72 @@ juicefs sync --force-update s3://ABCDEFG:[email protected]/

##### 后缀匹配

后缀匹配指通配符规则一定是匹配到路径的末尾。如:`foo` 匹配 `foo``xx/foo`,但不匹配 `xx/foo1``foo/xx`
后缀匹配指只要待匹配的路径的层级后缀符合通配符规则达到匹配要求。这里需要注意的是通配符规则一定是匹配到路径的末尾,并且路径被匹配的部分必须是包含完整的(目录或文件)名称,不可从名称中间切开。如:`foo` 匹配 `foo``xx/foo`,但不匹配 `xx/foo1``foo/xx`,`xx/2foo`

根据后缀匹配的规则可以总结以下要点:

+ 若匹配模式以斜线 `/` 结尾,将只匹配目录,而不匹配普通文件。

+ 如果匹配模式中包含了一个 `/` (不包括以斜线结尾的情况) 或 `**`,则表示对包括前导目录的全路径进行匹配。如果匹配模式中不包括 `/``**`,则表示只对全路径尾部的路径元素进行匹配。

##### 前缀匹配
##### 完整路径匹配

前缀匹配指如果匹配模式以斜线 `/` 开头,它表示锚定层次结构中某个特定位置的文件,否则将表示匹配路径名的结尾这有点类似于正则表达式中的行首 `^`。因此 `/foo` 匹配的是传输中根目录的 `foo` 文件。这种情况可以理解为后缀匹配的一种特殊情况,按照后缀匹配原理依旧行的通,不过也可以简单的理解为如果匹配模式以 `/` 开头时就是前缀匹配
完整路径匹配指如果匹配模式以斜线 `/` 开头,它表示锚定层次结构中某个特定位置的文件,否则将表示匹配路径名的结尾这有点类似于正则表达式中的行首 `^`。因此 `/foo` 匹配的是传输中根目录的 `foo` 文件。

#### 过滤模式

过滤模式指的是如何处理待匹配的路径,是单层过滤模式还是层级过滤模式。`sync` 命令支持两种过滤模式,单层匹配模式和层级过滤模式。默认情况下,`sync` 命令使用层级过滤模式,可以通过 `--match-full-path` 参数来选择是否开启使用单层过滤模式。默认情况下,`sync` 命令使用层级过滤模式。

##### 单层过滤模式

![单层过滤示例图](../images/sync-single-layer-filtration.png)
![单层过滤示例图](../images/sync-single-layer-filtration.svg)

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

例如现有对象 `a1/b1/c1.txt``--include a*.txt --inlude c1.txt --exclude c*.txt`。直接将 `a1/b1/c1.txt` 这个字符串与 `--include a*.txt``--inlude c1.txt``--exclude c*.txt` 三个模式进行依次匹配。
例如现有对象 `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` 的最终匹配结果为包含
2. 尝试下一个规则 `a1/b1/c1.txt``--inlude c1.txt` 尝试匹配,此时根据后缀匹配原理,将会匹配成功。直接返回 `a1/b1/c1.txt` 的最终匹配结果为“包含”

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

以下是一些 `exclude/include` 规则全路径匹配模式的例子
以下是一些 `exclude/include` 规则单层过滤模式的例子

+ `--exclude *.o` 将排除所有文件名能匹配 `*.o` 的文件。
+ `--exclude /foo**` 将排除传输中根目录名为 `foo` 的文件或目录。
+ `--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 *` 排除掉)
+ 同时使用 `--include foo/bar.c --exclude *` 将只包含 `foo` 目录和 `foo/bar.c`

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

##### 层级过滤模式

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

层级过滤的核心是将先待匹配的对象路径按照路径层级逐层增加的子路径元素依次组成序列,比如原始路径为 `a1/b1/c1.txt` 的对象层级过滤的序列就是 `a1`,`a1/b1`,`a1/b1/c1.txt`
然后将这这个序列中的每个元素都当成单层过滤中的原始路径,依次执行单次过滤。某层的单次过滤中如过匹配上了某个模式,则直接返回该模式的行为结果作为整个层级匹配原始对象的结果。如过某层的所有规则都未匹配,则进入下一层级,如果所有层级未匹配则返回默认的行为——包含。
层级过滤的核心是先将待匹配的对象路径按照路径层级逐层增加的子路径元素依次组成序列,比如原始路径为 `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`,可以结合层级过滤图片分析步骤,在这个例子中途中途中子路径 1 到子路径 n 就分别是 `a1`,`a1/b1`,`a1/b1/c1.txt`
例如现有对象 `a1/b1/c1.txt``--include a*.txt`, `--inlude c1.txt`, `--exclude c*.txt`,可以结合层级过滤图片分析步骤,在这个例子中子路径序列就分别是 `a1`,`a1/b1`,`a1/b1/c1.txt`
该例子的层级过滤具体步骤:

1. 第一层级的单层过滤,单层过滤的路径是 `a1`,模式序列是 `--include a*.txt`, `--inlude c1.txt`, `--exclude c*.txt`,根据单层匹配规则结果将会是,单层内全部未匹配。继续下一层级。
2. 第二层级的单层过滤,单层过滤的路径是 `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. 返回匹配成功的模式的行为,即 `a1/b1/c1.txt` 匹配上了 `--inlude c1.txt` 模式,所以最终结果是包含。
1. 第一层级的单层过滤,单层过滤的路径是 `a1`,模式序列是 `--include a*.txt`, `--inlude c1.txt`, `--exclude c*.txt`,根据单层匹配规则,结果将会是单层内全部未匹配。继续下一层级。
2. 第二层级的单层过滤,单层过滤的路径是 `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. 匹配未到最后一层,在某层提前匹配成功,此时会直接返回匹配成功的模式的行为作为整个层级过滤的最终结果
2. 所有层级都未匹配成功,此时将会返回默认的行为作为最终结果——包含
1. 匹配未到最后一层,在某层提前匹配成功,此时如果是 exclude 模式则直接返回“排除”作为整个层级过滤的最终结果,如果是 include 模式则直接进入下一层级过滤
2. 所有过滤层级都已经执行完毕,但都未匹配上,此时也将会返回默认的行为作为最终结果——“包含”

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

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

Expand All @@ -265,7 +268,7 @@ juicefs sync --force-update s3://ABCDEFG:[email protected]/
+ `--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 模式匹配将无效,这在使用尾随`*`时尤为重要。例如,下面的例子不会正常工作:
+ 对于 `dir_name/***` 来说,它将匹配 dir_name 下的所有层次的文件。注意,每个子路径元素会自顶向下逐层,被访问因此 `include/exclude` 匹配模式会对每个子路径元素的全路径名进行递归 (例如,要包含 `/foo/bar/baz`,则`/foo``/foo/bar`必须不能被排除)。实际上,排除匹配模式在发现有文件要传输时,此文件所在目录层次的排除遍历会被短路。如果排除了某个父目录,则更深层次的 include 模式匹配将无效,这在使用尾随`*`时尤为重要。例如,下面的例子不会正常工作:

```
--include='/some/path/this-file-will-not-be-found'
Expand All @@ -283,7 +286,7 @@ juicefs sync --force-update s3://ABCDEFG:[email protected]/
--exclude *
```

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

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

Expand Down
Binary file removed docs/zh_cn/images/sync-hierarchical-filtration.png
Binary file not shown.
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.
Binary file removed docs/zh_cn/images/sync-single-layer-filtration.png
Binary file not shown.
Loading

0 comments on commit d038314

Please sign in to comment.