Is there any built-in or straightforward way to match paths recursively with double asterisk, e.g. like zsh does?
For example, with
path = 'foo/bar/ham/spam/eggs.py'
I can use fnmatch to test it with
fnmatch(path, 'foo/bar/ham/*/*.py'
Although, I would like to be able to do:
fnmatch(path, 'foo/**/*.py')
I know that fnmatch maps its pattern to regex, so in the words case I can roll my own fnmatch with additional **
pattern, but maybe there is an easier way
If you look into fnmatch source code closely, it internally converts the pattern to a regular expression, mapping *
into .*
(and not [^/]*
or similar) and thus does not care anything for directory separators /
- unlike UNIX shells:
while i < n:
c = pat[i]
i = i+1
if c == '*':
res = res + '.*'
elif c == '?':
res = res + '.'
elif c == '[':
...
Thus
>>> fnmatch.fnmatch('a/b/d/c', 'a/*/c')
True
>>> fnmatch.fnmatch('a/b/d/c', 'a/*************c')
True
For an fnmatch variant that works on paths, you can use a library called wcmatch which implements a globmatch
function that matches a path with the same logic that glob
crawls a filesystem with. You can control the enabled features with flags, in this case, we enable GLOBSTAR
(using **
for recursive directory search).
>>> from wcmatch import glob
>>> glob.globmatch('some/file/path/filename.txt', 'some/**/*.txt', flags=glob.GLOBSTAR)
True
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With