0

我有一个相对于根目录的文件路径列表,并试图确定哪个将与 glob 模式匹配。Dir.glob(<my_glob_pattern>)如果所有文件都在我的文件系统上并且我从根目录运行,我正在尝试获得相同的结果。

如果这是文件路径列表:

foo/index.md
foo/bar/index.md
foo/bar/baz/index.md
foo/bar/baz/qux/index.md

这是全局模式:

foo/bar/*.md

如果文件存在于我的文件系统中,则Dir.glob('foo/bar/*.md')仅返回foo/bar/index.md.

glob文档提到fnmatch,我尝试使用它,但发现该模式foo/bar/*.md匹配任意数量的嵌套子目录中的.md文件,类似于目录Dir.glob('foo/bar/**/*.md')的直接foo/bar子目录:

my_glob = 'foo/bar/*.md'

filepaths = [
  'foo/index.md',
  'foo/bar/index.md',
  'foo/bar/baz/index.md',
  'foo/bar/baz/qux/index.md',
]

# Using the provided filepaths
filepaths_that_match_pattern = filepaths.select{|path| File.fnmatch?(my_glob, path)}.sort

# If the filepaths actually existed on my filesystem
filepaths_found_by_glob = Dir.glob(my_glob).sort

raise Exception.new("They don't match!") unless filepaths_that_match_pattern == filepaths_found_by_glob

我[错误地]期望上面的代码可以工作,但filepaths_found_by_glob只包含直接子代,同时也filepaths_that_match_pattern包含所有嵌套的子代。

如何Dir.glob在文件系统上没有文件路径的情况下获得相同的结果?

4

2 回答 2

0

File::FNM_PATHNAME您可以在调用File.fnmatch函数时使用该标志。所以你的函数调用看起来像这样 -File.fnmatch(pattern, path, File::FNM_PATHNAME)

您可以在此处查看与其用法相关的示例:https ://apidock.com/ruby/File/fnmatch/class

于 2021-12-15T11:56:03.760 回答
-1

不要使用File.fnmatch,而是使用Pathname.fnmatch

require 'pathname'

PATTERN = 'foo/bar/*.md'

%w[
  foo/index.md
  foo/bar/index.md
  foo/bar/baz/index.md
  foo/bar/baz/qux/index.md
].each do |p|

  puts 'path: %-24s %s' % [
    p, 
    Pathname.new(p).fnmatch(PATTERN) ? 'matches' : 'does not match'
  ]
end

# >> path: foo/index.md             does not match
# >> path: foo/bar/index.md         matches
# >> path: foo/bar/baz/index.md     matches
# >> path: foo/bar/baz/qux/index.md matches

文件假定驱动器上存在文件或路径,而路径名:

路径名代表文件系统上的文件或目录的名称,但不代表文件本身。

另外,关于使用Dir.glob:小心使用它。它会立即尝试查找驱动器上匹配并返回命中的每个文件或路径。在一个大的或慢的驱动器上,或者一个写得不好的模式上,例如在调试或测试时,你的代码可能会被捆绑很长时间,或者让 Ruby 或运行 Ruby 的机器陷入困境,并且如果您正在检查共享或远程驱动器,它只会变得更糟。作为可能发生的情况的示例,请在命令行中尝试以下操作,但要准备好Cntrl+C重新获得控制权:

ls /**/*

相反,我建议使用标准库中的Find类,因为它会遍历匹配项。有关示例,请参阅该文档。

于 2020-04-08T23:39:39.317 回答