{"id":13582135,"url":"https://github.com/bmatcuk/doublestar","last_synced_at":"2025-05-13T17:13:44.711Z","repository":{"id":24602884,"uuid":"28011464","full_name":"bmatcuk/doublestar","owner":"bmatcuk","description":"Implements support for double star (**) matches in golang's path.Match and filepath.Glob.","archived":false,"fork":false,"pushed_at":"2025-01-25T22:09:24.000Z","size":275,"stargazers_count":567,"open_issues_count":10,"forks_count":56,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-04-24T03:49:24.825Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"JohnSundell/ShellOut","license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bmatcuk.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"bmatcuk"}},"created_at":"2014-12-14T23:08:34.000Z","updated_at":"2025-04-23T21:07:01.000Z","dependencies_parsed_at":"2023-02-12T23:30:45.942Z","dependency_job_id":"8cd6ed11-54f8-4f40-8813-991611810e09","html_url":"https://github.com/bmatcuk/doublestar","commit_stats":{"total_commits":115,"total_committers":13,"mean_commits":8.846153846153847,"dds":"0.22608695652173916","last_synced_commit":"180028ba525d3116cc917ac3179e79428acfd89c"},"previous_names":[],"tags_count":50,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bmatcuk%2Fdoublestar","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bmatcuk%2Fdoublestar/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bmatcuk%2Fdoublestar/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bmatcuk%2Fdoublestar/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bmatcuk","download_url":"https://codeload.github.com/bmatcuk/doublestar/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253990498,"owners_count":21995776,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T15:02:26.861Z","updated_at":"2025-05-13T17:13:39.697Z","avatar_url":"https://github.com/bmatcuk.png","language":"Go","funding_links":["https://github.com/sponsors/bmatcuk"],"categories":["Go"],"sub_categories":[],"readme":"# doublestar\n\nPath pattern matching and globbing supporting `doublestar` (`**`) patterns.\n\n[![PkgGoDev](https://pkg.go.dev/badge/github.com/bmatcuk/doublestar)](https://pkg.go.dev/github.com/bmatcuk/doublestar/v4)\n[![Release](https://img.shields.io/github/release/bmatcuk/doublestar.svg?branch=master)](https://github.com/bmatcuk/doublestar/releases)\n[![Build Status](https://github.com/bmatcuk/doublestar/actions/workflows/test.yml/badge.svg)](https://github.com/bmatcuk/doublestar/actions)\n[![codecov.io](https://img.shields.io/codecov/c/github/bmatcuk/doublestar.svg?branch=master)](https://codecov.io/github/bmatcuk/doublestar?branch=master)\n[![Sponsor](https://img.shields.io/static/v1?label=Sponsor\u0026message=%E2%9D%A4\u0026logo=GitHub\u0026color=%23fe8e86)](https://github.com/sponsors/bmatcuk)\n\n## About\n\n#### [Upgrading?](UPGRADING.md)\n\n**doublestar** is a [golang] implementation of path pattern matching and\nglobbing with support for \"doublestar\" (aka globstar: `**`) patterns.\n\ndoublestar patterns match files and directories recursively. For example, if\nyou had the following directory structure:\n\n```bash\ngrandparent\n`-- parent\n    |-- child1\n    `-- child2\n```\n\nYou could find the children with patterns such as: `**/child*`,\n`grandparent/**/child?`, `**/parent/*`, or even just `**` by itself (which will\nreturn all files and directories recursively).\n\nBash's globstar is doublestar's inspiration and, as such, works similarly.\nNote that the doublestar must appear as a path component by itself. A pattern\nsuch as `/path**` is invalid and will be treated the same as `/path*`, but\n`/path*/**` should achieve the desired result. Additionally, `/path/**` will\nmatch all directories and files under the path directory, but `/path/**/` will\nonly match directories.\n\nv4 is a complete rewrite with a focus on performance. Additionally,\n[doublestar] has been updated to use the new [io/fs] package for filesystem\naccess. As a result, it is only supported by [golang] v1.16+.\n\n## Installation\n\n**doublestar** can be installed via `go get`:\n\n```bash\ngo get github.com/bmatcuk/doublestar/v4\n```\n\nTo use it in your code, you must import it:\n\n```go\nimport \"github.com/bmatcuk/doublestar/v4\"\n```\n\n## Usage\n\n### ErrBadPattern\n\n```go\ndoublestar.ErrBadPattern\n```\n\nReturned by various functions to report that the pattern is malformed. At the\nmoment, this value is equal to `path.ErrBadPattern`, but, for portability, this\nequivalence should probably not be relied upon.\n\n### Match\n\n```go\nfunc Match(pattern, name string) (bool, error)\n```\n\nMatch returns true if `name` matches the file name `pattern` ([see\n\"patterns\"]). `name` and `pattern` are split on forward slash (`/`) characters\nand may be relative or absolute.\n\nMatch requires pattern to match all of name, not just a substring. The only\npossible returned error is `ErrBadPattern`, when pattern is malformed.\n\nNote: this is meant as a drop-in replacement for `path.Match()` which always\nuses `'/'` as the path separator. If you want to support systems which use a\ndifferent path separator (such as Windows), what you want is `PathMatch()`.\nAlternatively, you can run `filepath.ToSlash()` on both pattern and name and\nthen use this function.\n\nNote: users should _not_ count on the returned error,\n`doublestar.ErrBadPattern`, being equal to `path.ErrBadPattern`.\n\n\n### MatchUnvalidated\n\n```go\nfunc MatchUnvalidated(pattern, name string) bool\n```\n\nMatchUnvalidated can provide a small performance improvement if you don't care\nabout whether or not the pattern is valid (perhaps because you already ran\n`ValidatePattern`). Note that there's really only one case where this\nperformance improvement is realized: when pattern matching reaches the end of\n`name` before reaching the end of `pattern`, such as `Match(\"a/b/c\", \"a\")`.\n\n\n### PathMatch\n\n```go\nfunc PathMatch(pattern, name string) (bool, error)\n```\n\nPathMatch returns true if `name` matches the file name `pattern` ([see\n\"patterns\"]). The difference between Match and PathMatch is that PathMatch will\nautomatically use your system's path separator to split `name` and `pattern`.\nOn systems where the path separator is `'\\'`, escaping will be disabled.\n\nNote: this is meant as a drop-in replacement for `filepath.Match()`. It assumes\nthat both `pattern` and `name` are using the system's path separator. If you\ncan't be sure of that, use `filepath.ToSlash()` on both `pattern` and `name`,\nand then use the `Match()` function instead.\n\n\n### PathMatchUnvalidated\n\n```go\nfunc PathMatchUnvalidated(pattern, name string) bool\n```\n\nPathMatchUnvalidated can provide a small performance improvement if you don't\ncare about whether or not the pattern is valid (perhaps because you already ran\n`ValidatePattern`). Note that there's really only one case where this\nperformance improvement is realized: when pattern matching reaches the end of\n`name` before reaching the end of `pattern`, such as `Match(\"a/b/c\", \"a\")`.\n\n\n### GlobOption\n\nOptions that may be passed to `Glob`, `GlobWalk`, or `FilepathGlob`. Any number\nof options may be passed to these functions, and in any order, as the last\nargument(s).\n\n```go\nWithFailOnIOErrors()\n```\n\nIf passed, doublestar will abort and return IO errors when encountered. Note\nthat if the glob pattern references a path that does not exist (such as\n`nonexistent/path/*`), this is _not_ considered an IO error: it is considered a\npattern with no matches.\n\n```go\nWithFailOnPatternNotExist()\n```\n\nIf passed, doublestar will abort and return `doublestar.ErrPatternNotExist` if\nthe pattern references a path that does not exist before any meta characters\nsuch as `nonexistent/path/*`. Note that alts (ie, `{...}`) are expanded before\nthis check. In other words, a pattern such as `{a,b}/*` may fail if either `a`\nor `b` do not exist but `*/{a,b}` will never fail because the star may match\nnothing.\n\n```go\nWithFilesOnly()\n```\n\nIf passed, doublestar will only return \"files\" from `Glob`, `GlobWalk`, or\n`FilepathGlob`. In this context, \"files\" are anything that is not a directory\nor a symlink to a directory.\n\nNote: if combined with the WithNoFollow option, symlinks to directories _will_\nbe included in the result since no attempt is made to follow the symlink.\n\n```go\nWithNoFollow()\n```\n\nIf passed, doublestar will not follow symlinks while traversing the filesystem.\nHowever, due to io/fs's _very_ poor support for querying the filesystem about\nsymlinks, there's a caveat here: if part of the pattern before any meta\ncharacters contains a reference to a symlink, it will be followed. For example,\na pattern such as `path/to/symlink/*` will be followed assuming it is a valid\nsymlink to a directory. However, from this same example, a pattern such as\n`path/to/**` will not traverse the `symlink`, nor would `path/*/symlink/*`\n\nNote: if combined with the WithFilesOnly option, symlinks to directories _will_\nbe included in the result since no attempt is made to follow the symlink.\n\n### Glob\n\n```go\nfunc Glob(fsys fs.FS, pattern string, opts ...GlobOption) ([]string, error)\n```\n\nGlob returns the names of all files matching pattern or nil if there is no\nmatching file. The syntax of patterns is the same as in `Match()`. The pattern\nmay describe hierarchical names such as `usr/*/bin/ed`.\n\nGlob ignores file system errors such as I/O errors reading directories by\ndefault. The only possible returned error is `ErrBadPattern`, reporting that\nthe pattern is malformed.\n\nTo enable aborting on I/O errors, the `WithFailOnIOErrors` option can be\npassed.\n\nNote: this is meant as a drop-in replacement for `io/fs.Glob()`. Like\n`io/fs.Glob()`, this function assumes that your pattern uses `/` as the path\nseparator even if that's not correct for your OS (like Windows). If you aren't\nsure if that's the case, you can use `filepath.ToSlash()` on your pattern\nbefore calling `Glob()`.\n\nLike `io/fs.Glob()`, patterns containing `/./`, `/../`, or starting with `/`\nwill return no results and no errors. This seems to be a [conscious\ndecision](https://github.com/golang/go/issues/44092#issuecomment-774132549),\neven if counter-intuitive. You can use [SplitPattern] to divide a pattern into\na base path (to initialize an `FS` object) and pattern.\n\nNote: users should _not_ count on the returned error,\n`doublestar.ErrBadPattern`, being equal to `path.ErrBadPattern`.\n\n### GlobWalk\n\n```go\ntype GlobWalkFunc func(path string, d fs.DirEntry) error\n\nfunc GlobWalk(fsys fs.FS, pattern string, fn GlobWalkFunc, opts ...GlobOption) error\n```\n\nGlobWalk calls the callback function `fn` for every file matching pattern.  The\nsyntax of pattern is the same as in Match() and the behavior is the same as\nGlob(), with regard to limitations (such as patterns containing `/./`, `/../`,\nor starting with `/`). The pattern may describe hierarchical names such as\nusr/*/bin/ed.\n\nGlobWalk may have a small performance benefit over Glob if you do not need a\nslice of matches because it can avoid allocating memory for the matches.\nAdditionally, GlobWalk gives you access to the `fs.DirEntry` objects for each\nmatch, and lets you quit early by returning a non-nil error from your callback\nfunction. Like `io/fs.WalkDir`, if your callback returns `SkipDir`, GlobWalk\nwill skip the current directory. This means that if the current path _is_ a\ndirectory, GlobWalk will not recurse into it. If the current path is not a\ndirectory, the rest of the parent directory will be skipped.\n\nGlobWalk ignores file system errors such as I/O errors reading directories by\ndefault. GlobWalk may return `ErrBadPattern`, reporting that the pattern is\nmalformed.\n\nTo enable aborting on I/O errors, the `WithFailOnIOErrors` option can be\npassed.\n\nAdditionally, if the callback function `fn` returns an error, GlobWalk will\nexit immediately and return that error.\n\nLike Glob(), this function assumes that your pattern uses `/` as the path\nseparator even if that's not correct for your OS (like Windows). If you aren't\nsure if that's the case, you can use filepath.ToSlash() on your pattern before\ncalling GlobWalk().\n\nNote: users should _not_ count on the returned error,\n`doublestar.ErrBadPattern`, being equal to `path.ErrBadPattern`.\n\n### FilepathGlob\n\n```go\nfunc FilepathGlob(pattern string, opts ...GlobOption) (matches []string, err error)\n```\n\nFilepathGlob returns the names of all files matching pattern or nil if there is\nno matching file. The syntax of pattern is the same as in Match(). The pattern\nmay describe hierarchical names such as usr/*/bin/ed.\n\nFilepathGlob ignores file system errors such as I/O errors reading directories\nby default. The only possible returned error is `ErrBadPattern`, reporting that\nthe pattern is malformed.\n\nTo enable aborting on I/O errors, the `WithFailOnIOErrors` option can be\npassed.\n\nNote: FilepathGlob is a convenience function that is meant as a drop-in\nreplacement for `path/filepath.Glob()` for users who don't need the\ncomplication of io/fs. Basically, it:\n\n* Runs `filepath.Clean()` and `ToSlash()` on the pattern\n* Runs `SplitPattern()` to get a base path and a pattern to Glob\n* Creates an FS object from the base path and `Glob()s` on the pattern\n* Joins the base path with all of the matches from `Glob()`\n\nReturned paths will use the system's path separator, just like\n`filepath.Glob()`.\n\nNote: the returned error `doublestar.ErrBadPattern` is not equal to\n`filepath.ErrBadPattern`.\n\n### SplitPattern\n\n```go\nfunc SplitPattern(p string) (base, pattern string)\n```\n\nSplitPattern is a utility function. Given a pattern, SplitPattern will return\ntwo strings: the first string is everything up to the last slash (`/`) that\nappears _before_ any unescaped \"meta\" characters (ie, `*?[{`).  The second\nstring is everything after that slash. For example, given the pattern:\n\n```\n../../path/to/meta*/**\n             ^----------- split here\n```\n\nSplitPattern returns \"../../path/to\" and \"meta*/**\". This is useful for\ninitializing os.DirFS() to call Glob() because Glob() will silently fail if\nyour pattern includes `/./` or `/../`. For example:\n\n```go\nbase, pattern := SplitPattern(\"../../path/to/meta*/**\")\nfsys := os.DirFS(base)\nmatches, err := Glob(fsys, pattern)\n```\n\nIf SplitPattern cannot find somewhere to split the pattern (for example,\n`meta*/**`), it will return \".\" and the unaltered pattern (`meta*/**` in this\nexample).\n\nNote that SplitPattern will also unescape any meta characters in the returned\nbase string, so that it can be passed straight to os.DirFS().\n\nOf course, it is your responsibility to decide if the returned base path is\n\"safe\" in the context of your application. Perhaps you could use Match() to\nvalidate against a list of approved base directories?\n\n### ValidatePattern\n\n```go\nfunc ValidatePattern(s string) bool\n```\n\nValidate a pattern. Patterns are validated while they run in Match(),\nPathMatch(), and Glob(), so, you normally wouldn't need to call this.  However,\nthere are cases where this might be useful: for example, if your program allows\na user to enter a pattern that you'll run at a later time, you might want to\nvalidate it.\n\nValidatePattern assumes your pattern uses '/' as the path separator.\n\n### ValidatePathPattern\n\n```go\nfunc ValidatePathPattern(s string) bool\n```\n\nLike ValidatePattern, only uses your OS path separator. In other words, use\nValidatePattern if you would normally use Match() or Glob(). Use\nValidatePathPattern if you would normally use PathMatch(). Keep in mind, Glob()\nrequires '/' separators, even if your OS uses something else.\n\n### Patterns\n\n**doublestar** supports the following special terms in the patterns:\n\nSpecial Terms | Meaning\n------------- | -------\n`*`           | matches any sequence of non-path-separators\n`/**/`        | matches zero or more directories\n`?`           | matches any single non-path-separator character\n`[class]`     | matches any single non-path-separator character against a class of characters ([see \"character classes\"])\n`{alt1,...}`  | matches a sequence of characters if one of the comma-separated alternatives matches\n\nAny character with a special meaning can be escaped with a backslash (`\\`).\n\nA doublestar (`**`) should appear surrounded by path separators such as `/**/`.\nA mid-pattern doublestar (`**`) behaves like bash's globstar option: a pattern\nsuch as `path/to/**.txt` would return the same results as `path/to/*.txt`. The\npattern you're looking for is `path/to/**/*.txt`.\n\n#### Character Classes\n\nCharacter classes support the following:\n\nClass      | Meaning\n---------- | -------\n`[abc123]` | matches any single character within the set\n`[a-z0-9]` | matches any single character in the range a-z or 0-9\n`[125-79]` | matches any single character within the set 129, or the range 5-7\n`[^class]` | matches any single character which does *not* match the class\n`[!class]` | same as `^`: negates the class\n\n## Performance\n\n```\ngoos: darwin\ngoarch: amd64\npkg: github.com/bmatcuk/doublestar/v4\ncpu: Intel(R) Core(TM) i7-4870HQ CPU @ 2.50GHz\nBenchmarkMatch-8                  285639              3868 ns/op               0 B/op          0 allocs/op\nBenchmarkGoMatch-8                286945              3726 ns/op               0 B/op          0 allocs/op\nBenchmarkPathMatch-8              320511              3493 ns/op               0 B/op          0 allocs/op\nBenchmarkGoPathMatch-8            304236              3434 ns/op               0 B/op          0 allocs/op\nBenchmarkGlob-8                      466           2501123 ns/op          190225 B/op       2849 allocs/op\nBenchmarkGlobWalk-8                  476           2536293 ns/op          184017 B/op       2750 allocs/op\nBenchmarkGoGlob-8                    463           2574836 ns/op          194249 B/op       2929 allocs/op\n```\n\nThese benchmarks (in `doublestar_test.go`) compare Match() to path.Match(),\nPathMath() to filepath.Match(), and Glob() + GlobWalk() to io/fs.Glob(). They\nonly run patterns that the standard go packages can understand as well (so, no\n`{alts}` or `**`) for a fair comparison. Of course, alts and doublestars will\nbe less performant than the other pattern meta characters.\n\nAlts are essentially like running multiple patterns, the number of which can\nget large if your pattern has alts nested inside alts. This affects both\nmatching (ie, Match()) and globbing (Glob()).\n\n`**` performance in matching is actually pretty similar to a regular `*`, but\ncan cause a large number of reads when globbing as it will need to recursively\ntraverse your filesystem.\n\n## Sponsors\nI started this project in 2014 in my spare time and have been maintaining it\never since. In that time, it has grown into one of the most popular globbing\nlibraries in the Go ecosystem. So, if **doublestar** is a useful library in\nyour project, consider [sponsoring] my work! I'd really appreciate it!\n\nThanks for sponsoring me!\n\n## License\n\n[MIT License](LICENSE)\n\n[SplitPattern]: #splitpattern\n[doublestar]: https://github.com/bmatcuk/doublestar\n[golang]: http://golang.org/\n[io/fs]: https://pkg.go.dev/io/fs\n[see \"character classes\"]: #character-classes\n[see \"patterns\"]: #patterns\n[sponsoring]: https://github.com/sponsors/bmatcuk\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbmatcuk%2Fdoublestar","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbmatcuk%2Fdoublestar","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbmatcuk%2Fdoublestar/lists"}