bmatcuk/doublestar

GitHub: bmatcuk/doublestar

Go 语言的路径模式匹配库,为标准库增加双星号(**)递归 glob 匹配支持。

Stars: 712 | Forks: 72

# doublestar 支持 `doublestar` (`**`) 模式的路径模式匹配和 glob 匹配。 [![PkgGoDev](https://pkg.go.dev/badge/github.com/bmatcuk/doublestar)](https://pkg.go.dev/github.com/bmatcuk/doublestar/v4) [![发布](https://img.shields.io/github/release/bmatcuk/doublestar.svg?branch=master)](https://github.com/bmatcuk/doublestar/releases) [![构建状态](https://github.com/yuin/goldmark/actions?query=workflow:test](https://static.pigsec.cn/wp-content/uploads/repos/cas/96/96516d7a51f21139fae950e3129296fedeb5ab5f68f6a4dd1d280445b5bfdb15.svg)](https://github.com/bmatcuk/doublestar/actions) [![codecov.io](https://img.shields.io/codecov/c/github/bmatcuk/doublestar.svg?branch=master)](https://codecov.io/github/bmatcuk/doublestar?branch=master) [![赞助](https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&color=%23fe8e86)](https://github.com/sponsors/bmatcuk) ## 关于 #### [要升级吗?](UPGRADING.md) **doublestar** 是一个 [golang] 的实现,用于路径模式匹配和 支持 "doublestar"(又称 globstar:`**`)模式的 glob 匹配。 doublestar 模式可以递归匹配文件和目录。例如,如果你 有以下目录结构: ``` grandparent `-- parent |-- child1 `-- child2 ``` 你可以使用以下模式来查找子项:`**/child*`、 `grandparent/**/child?`、`**/parent/*`,甚至单独使用 `**`(这将 递归返回所有文件和目录)。 Bash 的 globstar 是 doublestar 的灵感来源,因此它们的工作方式类似。 请注意,doublestar 必须作为一个独立的路径组件出现。像 `/path**` 这样的模式是无效的,它将被当作 `/path*` 处理,但是 `/path*/**` 应该能达到你想要的结果。此外,`/path/**` 将 匹配 path 目录下的所有目录和文件,但 `/path/**/` 将 只匹配目录。 v4 是一次以性能为重点的完全重写。此外, [doublestar] 已更新为使用新的 [io/fs] 包进行文件系统 访问。因此,它仅受 [golang] v1.16+ 支持。 ## 安装 **doublestar** 可以通过 `go get` 安装: ``` go get github.com/bmatcuk/doublestar/v4 ``` 要在你的代码中使用它,你必须导入它: ``` import "github.com/bmatcuk/doublestar/v4" ``` ## 用法 ### ErrBadPattern ``` doublestar.ErrBadPattern ``` 由各种函数返回,以报告模式格式错误。目前, 该值等于 `path.ErrBadPattern`,但是为了可移植性,可能 不应依赖此等价性。 ### 匹配 ``` func Match(pattern, name string) (bool, error) ``` 如果 `name` 匹配文件名 `pattern`([参见“模式”]),Match 返回 true。 `name` 和 `pattern` 以正斜杠 (`/`) 字符分隔,可以是相对路径或 绝对路径。 Match 要求 pattern 匹配整个 name,而不仅仅是子字符串。唯一 可能返回的错误是 `ErrBadPattern`,此时表示 pattern 格式错误。 注意:这旨在作为 `path.Match()` 的直接替代品,后者始终 使用 `'/'` 作为路径分隔符。如果你想支持使用不同 路径分隔符(如 Windows)的系统,你需要的是 `PathMatch()`。 或者,你可以在 pattern 和 name 上运行 `filepath.ToSlash()`, 然后使用此函数。 注意:用户_不应_指望返回的错误 `doublestar.ErrBadPattern` 等于 `path.ErrBadPattern`。 ### MatchUnvalidated ``` func MatchUnvalidated(pattern, name string) bool ``` 如果你不关心 pattern 是否有效(可能因为你已经运行过 `ValidatePattern`),MatchUnvalidated 可以提供小幅度的性能提升。 请注意,实际上只有一种情况可以实现这种性能提升: 当模式匹配在到达 `pattern` 结尾之前到达了 `name` 的结尾时,例如 `Match("a/b/c", "a")`。 ### PathMatch ``` func PathMatch(pattern, name string) (bool, error) ``` 如果 `name` 匹配文件名 `pattern`([参见“模式”]),PathMatch 返回 true。 Match 和 PathMatch 之间的区别在于 PathMatch 会 自动使用你系统的路径分隔符来拆分 `name` 和 `pattern`。 在路径分隔符为 `'\'` 的系统上,转义将被禁用。 注意:这旨在作为 `filepath.Match()` 的直接替代品。它假定 `pattern` 和 `name` 都使用系统的路径分隔符。如果你 无法确定,请在 `pattern` 和 `name` 上使用 `filepath.ToSlash()`, 然后改用 `Match()` 函数。 ### PathMatchUnvalidated ``` func PathMatchUnvalidated(pattern, name string) bool ``` 如果你不关心 pattern 是否有效(可能因为你已经运行过 `ValidatePattern`),PathMatchUnvalidated 可以提供小幅度的性能提升。 请注意,实际上只有一种情况可以实现这种性能提升: 当模式匹配在到达 `pattern` 结尾之前到达了 `name` 的结尾时,例如 `Match("a/b/c", "a")`。 ### GlobOption 可以传递给 `Glob`、`GlobWalk` 或 `FilepathGlob` 的选项。可以将任意数量 的选项作为最后一个(或几个)参数以任意顺序传递给这些函数。 ``` WithCaseInsensitive() ``` WithCaseInsensitive 是一个可以传递给 Glob、GlobWalk 或 FilepathGlob 的选项。如果传递,doublestar 会将所有字母字符视为 不区分大小写(即 pattern 中的 "a" 将匹配 "a" 或 "A")。这 对于像 Windows 这样默认路径不区分大小写的平台很有用。 ``` WithFailOnIOErrors() ``` 如果传递,doublestar 将在中止并返回遇到的 IO 错误。请注意, 如果 glob 模式引用了不存在的路径(例如 `nonexistent/path/*`),这_不_被视为 IO 错误:它被视为 没有匹配项的模式。 ``` WithFailOnPatternNotExist() ``` 如果传递,如果模式在任何元字符之前引用了不存在的路径 (例如 `nonexistent/path/*`),doublestar 将中止并返回 `doublestar.ErrPatternNotExist`。 请注意,alts(即 `{...}`)会在此检查之前展开。换句话说,如果 `a` 或 `b` 不存在,像 `{a,b}/*` 这样的模式可能会失败,但 `*/{a,b}` 永远不会失败,因为星号可以匹配 无内容。 ``` WithFilesOnly() ``` 如果传递,doublestar 将仅从 `Glob`、`GlobWalk` 或 `FilepathGlob` 返回“文件”。在此上下文中,“文件”是指任何不是目录 或指向目录的 symlink 的对象。 注意:如果与 WithNoFollow 选项结合使用,指向目录的 symlink _将_ 包含在结果中,因为没有尝试去跟随该 symlink。 ``` WithNoFollow() ``` 如果传递,doublestar 在遍历文件系统时将不会跟随 symlink。 然而,由于 io/fs 对查询文件系统关于 symlink 的支持_非常_差,这里有一个注意事项:如果在任何元 字符之前的模式部分包含对 symlink 的引用,它将被跟随。例如, 像 `path/to/symlink/*` 这样的模式将被跟随,前提是它是一个有效 指向目录的 symlink。然而,在同一个示例中,像 `path/to/**` 这样的模式将不会遍历 `symlink`,`path/*/symlink/*` 也不会 注意:如果与 WithFilesOnly 选项结合使用,指向目录的 symlink _将_ 包含在结果中,因为没有尝试去跟随该 symlink。 ``` WithNoHidden() ``` 如果传递,在使用通配符时,doublestar 将不匹配隐藏文件和目录(那些 以点开头的文件和目录)。这遵循了传统的 shell glob 行为,即开头的 `*` 或 `?` 默认不会匹配点文件。 仍然可以通过在模式中显式包含隐藏文件来匹配它们。 例如,`.*` 将匹配隐藏文件,而 `.config/**` 将匹配 .config 目录内的文件。 规则是: - 对于 `**`:不进入隐藏目录 - 对于 `*` 或以 `?` 开头的模式:不匹配点文件或 目录 在 Windows 上,doublestar 将检查文件属性并以这种方式避开隐藏文件 和目录,而不是匹配文件名。因此,任何 带有 `*` 或 `?` 的模式都可能匹配到隐藏的文件/目录。 ### Glob ``` func Glob(fsys fs.FS, pattern string, opts ...GlobOption) ([]string, error) ``` Glob 返回所有匹配 pattern 的文件的名称,如果没有 匹配的文件,则返回 nil。pattern 的语法与 `Match()` 中的相同。pattern 可以描述分层名称,例如 `usr/*/bin/ed`。 Glob 默认忽略文件系统错误,例如读取目录时的 I/O 错误。 唯一可能返回的错误是 `ErrBadPattern`,报告 pattern 格式错误。 要启用在 I/O 错误时中止,可以传递 `WithFailOnIOErrors` 选项。 注意:这旨在作为 `io/fs.Glob()` 的直接替代品。与 `io/fs.Glob()` 一样,即使这对你的操作系统(如 Windows)来说是不正确的,此函数也假定你的模式使用 `/` 作为路径 分隔符。如果你不确定 是否如此,可以在调用 `Glob()` 之前在你的模式上使用 `filepath.ToSlash()`。 与 `io/fs.Glob()` 一样,包含 `/./`、`/../` 或以 `/` 开头的模式 将不返回任何结果,也不返回错误。这似乎是一个 [有意的 决定](https://github.com/golang/go/issues/44092#issuecomment-774132549), 即使这有些违背直觉。你可以使用 [SplitPattern] 将模式拆分为 基础路径(用于初始化 `FS` 对象)和模式。 注意:用户_不应_指望返回的错误 `doublestar.ErrBadPattern` 等于 `path.ErrBadPattern`。 ### GlobWalk ``` type GlobWalkFunc func(path string, d fs.DirEntry) error func GlobWalk(fsys fs.FS, pattern string, fn GlobWalkFunc, opts ...GlobOption) error ``` GlobWalk 为每个匹配模式的文件调用回调函数 `fn`。 pattern 的语法与 Match() 中的相同,并且在限制方面(例如包含 `/./`、`/../` 或以 `/` 开头的模式),其行为与 Glob() 相同。pattern 可以描述分层名称,例如 usr/*/bin/ed。 如果你不需要匹配项的切片,GlobWalk 可能比 Glob 具有轻微的性能优势, 因为它可以避免为匹配项分配内存。 此外,GlobWalk 让你可以访问每个 匹配项的 `fs.DirEntry` 对象,并允许你通过从回调 函数返回非 nil 错误来提前退出。与 `io/fs.WalkDir` 一样,如果你的回调返回 `SkipDir`,GlobWalk 将跳过当前目录。这意味着如果当前路径_是_一个 目录,GlobWalk 将不会递归进入其中。如果当前路径不是 目录,则父目录的其余部分将被跳过。 GlobWalk 默认忽略文件系统错误,例如读取目录时的 I/O 错误。 GlobWalk 可能会返回 `ErrBadPattern`,报告 pattern 格式错误。 要启用在 I/O 错误时中止,可以传递 `WithFailOnIOErrors` 选项。 此外,如果回调函数 `fn` 返回错误,GlobWalk 将 立即退出并返回该错误。 与 Glob() 一样,即使这对你的操作系统(如 Windows)来说是不正确的,此函数也假定你的模式使用 `/` 作为路径 分隔符。如果你不确定 是否如此,可以在调用 GlobWalk() 之前在你的模式上使用 filepath.ToSlash()。 注意:用户_不应_指望返回的错误 `doublestar.ErrBadPattern` 等于 `path.ErrBadPattern`。 ### FilepathGlob ``` func FilepathGlob(pattern string, opts ...GlobOption) (matches []string, err error) ``` FilepathGlob 返回所有匹配 pattern 的文件的名称,如果没有 匹配的文件,则返回 nil。pattern 的语法与 Match() 中的相同。 pattern 可以描述分层名称,例如 usr/*/bin/ed。 FilepathGlob 默认忽略文件系统错误,例如读取目录 时的 I/O 错误。唯一可能返回的错误是 `ErrBadPattern`,报告 pattern 格式错误。 要启用在 I/O 错误时中止,可以传递 `WithFailOnIOErrors` 选项。 注意:FilepathGlob 是一个为了方便而提供的函数,旨在作为不需要 io/fs 复杂性的用户的 `path/filepath.Glob()` 的直接替代品。基本上,它: * 在模式上运行 `filepath.Clean()` 和 `ToSlash()` * 运行 `SplitPattern()` 以获取基础路径和要 Glob 的模式 * 从基础路径创建一个 FS 对象,并在该模式上执行 `Glob()s` * 将基础路径与 `Glob()` 的所有匹配项连接起来 返回的路径将使用系统的路径分隔符,就像 `filepath.Glob()` 一样。 注意:返回的错误 `doublestar.ErrBadPattern` 不等于 `filepath.ErrBadPattern`。 ### SplitPattern ``` func SplitPattern(p string) (base, pattern string) ``` SplitPattern 是一个实用函数。给定一个模式,SplitPattern 将返回 两个字符串:第一个字符串是在任何未转义的“元”字符(即 `*?[{`)_之前_出现 的最后一个斜杠 (`/`) 之前的所有内容。第二 个字符串是该斜杠之后的所有内容。例如,给定模式: ``` ../../path/to/meta*/** ^----------- split here ``` SplitPattern 返回 "../../path/to" 和 "meta*/**"。这对于 初始化 os.DirFS() 以调用 Glob() 非常有用,因为如果你的 模式包含 `/./` 或 `/../`,Glob() 将会静默失败。例如: ``` base, pattern := SplitPattern("../../path/to/meta*/**") fsys := os.DirFS(base) matches, err := Glob(fsys, pattern) ``` 如果 SplitPattern 找不到拆分模式的地方(例如 `meta*/**`),它将返回 "." 和未更改的模式(在此 示例中为 `meta**`)。 请注意,SplitPattern 还会取消转义返回的 基础字符串中的任何元字符,以便它可以 直接传递给 os.DirFS()。 当然,你有责任决定返回的基础路径在你的应用程序上下文中是否是“安全”的。也许你可以使用 Match() 针对 已批准的基础目录列表进行验证? ### ValidatePattern ``` func ValidatePattern(s string) bool ``` 验证模式。在 Match()、 PathMatch() 和 Glob() 中运行时会进行模式验证,因此通常你不需要调用此函数。然而, 在某些情况下这可能会很有用:例如,如果你的程序允许用户输入一个你将在稍后运行的模式,你可能想要 验证它。 ValidatePattern 假定你的模式使用 '/' 作为路径分隔符。 ### ValidatePathPattern ``` func ValidatePathPattern(s string) bool ``` 与 ValidatePattern 类似,只是使用你的操作系统路径分隔符。换句话说,如果你通常会使用 Match() 或 Glob(),请使用 ValidatePattern。如果你通常会使用 PathMatch(),请使用 ValidatePathPattern。请记住,即使你的操作系统使用其他分隔符,Glob() 也需要 '/' 分隔符。 ### 模式 **doublestar** 在模式中支持以下特殊术语: 特殊术语 | 含义 ------------- | ------- `*` | 匹配任何非路径分隔符的序列 `/**/` | 匹配零个或多个目录 `?` | 匹配任何单个非路径分隔符的字符 `[class]` | 将任何单个非路径分隔符的字符与一类字符进行匹配([参见“字符类”]) `{alt1,...}` | 如果任何一个逗号分隔的备选项匹配,则匹配一个字符序列 任何具有特殊含义的字符都可以用反斜杠 (`\`) 转义。 doublestar (`**`) 应该被路径分隔符包围,例如 `/**/`。 模式中间的 doublestar (`**`) 行为类似于 bash 的 globstar 选项:像 `path/to/**.txt` 这样的模式将返回与 `path/to/*.txt` 相同的结果。你 要找的模式应该是 `path/to/**/*.txt`。 #### 字符类 字符类支持以下内容: 类 | 含义 ---------- | ------- `[abc123]` | 匹配集合中的任何单个字符 `[a-z0-9]` | 匹配 a-z 或 0-9 范围内的任何单个字符 `[125-79]` | 匹配集合 129 或范围 5-7 内的任何单个字符 `[^class]` | 匹配任何_不_匹配该类的单个字符 `[!class]` | 与 `^` 相同:否定该类 #### Glob 不是正则表达式 我偶尔会收到错误报告,说某些正则表达式风格的语法 不起作用,或者收到添加一些受正则表达式启发的 语法的功能请求。Glob 不是正则表达式。但是,如果 glob 不足以 满足你的过滤需求,我建议使用 `GlobWalk` 进行两阶段的 方法。类似以下的内容将帮助你入门: ``` var matches []string err := doublestar.GlobWalk(fsys, pattern, func(p string, d fs.DirEntry) error { if (customFilter(p, d)) { matches = append(matches, p) } else if (d.isDir()) { return doublestar.SkipDir } return nil }) return matches, err ``` 在这个示例中,`pattern` 应该是一个 glob,用于第一遍获取你可能感兴趣的文件;`customFilter` 是一个进行第 二遍筛选的函数。这第二遍可以是任何内容,包括正则表达式。 尝试构建一个 `pattern`,以减少你需要在第二遍 `customFilter` 中考虑的文件数量。 最后一点注意事项:空备选项可用于构建一些更复杂的 glob。例如,`some{thing,}` 将同时匹配 "something" 和 "some"。 备选项也可以嵌套,例如 `some{thing{new,},}`,它将匹配 "somethingnew"、"something" 和 "some"。 ## 性能 ``` goos: darwin goarch: amd64 pkg: github.com/bmatcuk/doublestar/v4 cpu: Intel(R) Core(TM) i7-4870HQ CPU @ 2.50GHz BenchmarkMatch-8 285639 3868 ns/op 0 B/op 0 allocs/op BenchmarkGoMatch-8 286945 3726 ns/op 0 B/op 0 allocs/op BenchmarkPathMatch-8 320511 3493 ns/op 0 B/op 0 allocs/op BenchmarkGoPathMatch-8 304236 3434 ns/op 0 B/op 0 allocs/op BenchmarkGlob-8 466 2501123 ns/op 190225 B/op 2849 allocs/op BenchmarkGlobWalk-8 476 2536293 ns/op 184017 B/op 2750 allocs/op BenchmarkGoGlob-8 463 2574836 ns/op 194249 B/op 2929 allocs/op ``` 这些基准测试(在 `doublestar_test.go` 中)将 Match() 与 path.Match() 进行比较, 将 PathMath() 与 filepath.Match() 进行比较,并将 Glob() + GlobWalk() 与 io/fs.Glob() 进行比较。它们 只运行标准 go 包也能理解的模式(因此,没有 `{alts}` 或 `**`),以进行公平比较。当然,与其他模式元字符相比,alts 和 doublestar 的 性能会 较低。 alts 本质上就像运行多个模式,如果你的模式中有嵌套的 alts,其数量可能会变得 很大。这会影响 匹配(即 Match())和 glob 匹配(Glob())。 `**` 在匹配方面的性能实际上与常规的 `*` 非常相似,但在进行 glob 匹配时 可能会导致大量的读取操作,因为它需要递归 遍历你的文件系统。 ## 赞助商 我在 2014 年的业余时间开始了这个项目,从那以后一直在维护它。 在那段时间里,它已经发展成为 Go 生态系统中最受欢迎的 glob 匹配 库之一。因此,如果 **doublestar** 是你 项目中的一个有用的库,请考虑[赞助]我的工作!我将不胜感激! 感谢你的赞助! ## 许可证 [MIT 许可证](LICENSE)
标签:EVTX分析, Go, Ruby工具, 开发工具库, 文件系统, 日志审计, 路径匹配, 通配符