Как получить пути к файлам, которые соответствуют глобус, не имея их в файловой системе - PullRequest
0 голосов
/ 09 апреля 2020

У меня есть список путей к файлам, относящихся к каталогу root, и я пытаюсь определить, какой из них будет соответствовать шаблону glob. Я пытаюсь получить те же результаты, которые получили бы, если бы все файлы были в моей файловой системе, и я запустил Dir.glob(<my_glob_pattern>) из root словаря.

Если это список путей к файлам:

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 без файловых путей в моей файловой системе?

1 Ответ

0 голосов
/ 09 апреля 2020

Не используйте 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 go для сканирования, и это только усугубляется, если вы проверяете общий или удаленный диск. В качестве примера того, что может произойти, попробуйте следующее в командной строке, но будьте готовы нажать Cntrl + C, чтобы восстановить контроль:

ls /**/*

Вместо этого я рекомендую использовать класс Find в стандартной библиотеке, так как он будет повторять совпадения. См. Эту документацию для примеров.

...