如何在Go中使用双星通配符(double star glob)?

huangapple go评论95阅读模式
英文:

How to use double star glob in Go?

问题

似乎Go是少数几种不支持双星号("globstar")语法进行文件匹配的语言之一。至少以下代码似乎不能按预期工作:

filepath.Glob(dir + "/**/*.bundle/*.txt")

我是否对filepath的实现有所遗漏?是否有支持此功能的库可用?

英文:

It seems like Go is one of few languages that does not seem to understand the double star ("globstar") syntax for file globbing. At least this does not seems to work as expected:

filepath.Glob(dir + "/**/*.bundle/*.txt")

Am I missing something about the filepath implementation?
Is there a library around that does support this?

答案1

得分: 10

filepath.Glob的实现在底层使用了filepath.Match。事实证明,该规范并没有涵盖非常常见的(.gitignorezsh)双星号模式。虽然不完全相同,但对于我的用例,我设法通过以下这个小函数解决了这个问题:

func glob(dir string, ext string) ([]string, error) {
  files := []string{}
  err := filepath.Walk(dir, func(path string, f os.FileInfo, err error) error {
    if filepath.Ext(path) == ext {
      files = append(files, path)
    }
    return nil
  })
  return files, err
}

我仍然希望能有一个更好的实现,能够正确匹配双星号模式。

英文:

The filepath.Glob implementation uses filepath.Match under the hood. Turns out the specs for that do not cover the quite common (.gitignore, zsh) double star pattern. By no means the same - but for my use case I managed to work around it with this little function:

func glob(dir string, ext string) ([]string, error) {

  files := []string{}
  err := filepath.Walk(dir, func(path string, f os.FileInfo, err error) error {
    if filepath.Ext(path) == ext {
      files = append(files, path)
    }
    return nil
  })

  return files, err
}

I am still open for a better implementation with proper double star matching.

答案2

得分: 6

我已经写了一个小的扩展库,支持双星号通配符。使用这个目录结构:

$ find a
a
a/b
a/b/c.d
a/b/c.d/e.f

你可以使用 a/**/*.* 来匹配 a 目录下包含点的所有内容,如下所示:

<!-- language: go -->

package main

import (
  "fmt"

  "github.com/yargevad/filepathx"
)

func main() {
  matches, err := filepathx.Glob("./a/**/*.*")
  if err != nil {
    panic(err)
  }

  for _, match := range matches {
    fmt.Printf("MATCH: [%v]\n", match)
  }
}

输出结果为:

$ go run example.go
MATCH: [a/b/c.d]
MATCH: [a/b/c.d/e.f]
英文:

I've written a small extension library that supports double star globbling. With this directory structure:

$ find a
a
a/b
a/b/c.d
a/b/c.d/e.f

You can use a/**/*.* to match everything under the a directory that contains a dot, like so:

<!-- language: go -->

package main

import (
  &quot;fmt&quot;

  &quot;github.com/yargevad/filepathx&quot;
)

func main() {
  matches, err := filepathx.Glob(&quot;./a/**/*.*&quot;)
  if err != nil {
    panic(err)
  }

  for _, match := range matches {
    fmt.Printf(&quot;MATCH: [%v]\n&quot;, match)
  }
}

Which outputs:

$ go run example.go
MATCH: [a/b/c.d]
MATCH: [a/b/c.d/e.f]

答案3

得分: 0

这里有一个类似的例子。你可以传递一个回调函数来过滤文件:

package main

import (
   "io/fs"
   "path/filepath"
)

func glob(root string, fn func(string) bool) []string {
   var files []string
   filepath.WalkDir(root, func(s string, d fs.DirEntry, e error) error {
      if fn(s) {
         files = append(files, s)
      }
      return nil
   })
   return files
}

func main() {
   files := glob(".", func(s string) bool {
      return filepath.Ext(s) == ".txt"
   })
   for _, file := range files {
      println(file)
   }
}
英文:

Here is something similar. You can pass a callback to filter the files:

package main

import (
   &quot;io/fs&quot;
   &quot;path/filepath&quot;
)

func glob(root string, fn func(string)bool) []string {
   var files []string
   filepath.WalkDir(root, func(s string, d fs.DirEntry, e error) error {
      if fn(s) {
         files = append(files, s)
      }
      return nil
   })
   return files
}

func main() {
   files := glob(&quot;.&quot;, func(s string) bool {
      return filepath.Ext(s) == &quot;.txt&quot;
   })
   for _, file := range files {
      println(file)
   }
}

huangapple
  • 本文由 发表于 2014年11月8日 04:22:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/26809484.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定