3

Ant 有一种选择文件组的好方法,最方便的是使用 ** 来指示目录树。例如

**/CVS/*            # All files immediately under a CVS directory.
mydir/mysubdir/**   # All files recursively under mysubdir

更多示例可以在这里看到:

http://ant.apache.org/manual/dirtasks.html

您将如何在 python 中实现它,以便您可以执行以下操作:

files = get_files("**/CVS/*")
for file in files:
    print file

=>
CVS/Repository
mydir/mysubdir/CVS/Entries
mydir/mysubdir/foo/bar/CVS/Entries
4

6 回答 6

4

对不起,这是你的 OP 之后的很长一段时间。我刚刚发布了一个 Python 包,它就是这样做的——它被称为 Formic,它可以在PyPI Cheeseshop 获得。使用 Formic,您的问题可以通过以下方式解决:

import formic
fileset = formic.FileSet(include="**/CVS/*", default_excludes=False)
for file_name in fileset.qualified_files():
    print file_name

有一点复杂:default_excludes。Formic 与 Ant 一样,默认情况下会排除 CVS 目录(因为大多数情况下从它们中收集文件以进行构建是危险的),该问题的默认答案将导致没有文件。设置 default_excludes=False 会禁用此行为。

于 2012-05-15T08:39:01.297 回答
3

一旦遇到 a **,您将不得不遍历整个目录结构,所以我认为此时最简单的方法是使用 os.walk 遍历目录,构造路径,然后检查如果它与模式匹配。您可能可以通过以下方式转换为正则表达式:

def glob_to_regex(pat, dirsep=os.sep):
    dirsep = re.escape(dirsep)
    print re.escape(pat)
    regex = (re.escape(pat).replace("\\*\\*"+dirsep,".*")
                           .replace("\\*\\*",".*")
                           .replace("\\*","[^%s]*" % dirsep)
                           .replace("\\?","[^%s]" % dirsep))
    return re.compile(regex+"$")

(但请注意,这并不是功能齐全 -[a-z]例如,它不支持样式 glob 模式,尽管这可能会被添加)。(第一个\*\*/匹配是覆盖像\*\*/CVS匹配这样的情况./CVS,以及只\*\*在尾部匹配。)

但是,显然你不想在不处理**模式时递归当前目录下的所有内容,所以我认为你需要一个两阶段的方法。我没有尝试实现以下内容,并且可能存在一些极端情况,但我认为它应该可以工作:

  1. 在目录分隔符上拆分模式。IEpat.split('/') -> ['**','CVS','*']

  2. 递归遍历目录,并查看此级别模式的相关部分。IE。n levels deep -> look at pat[n].

  3. 如果pat[n] == '**'切换到上述策略:

    • 重构模式dirsep.join(pat[n:])
    • 转换为正则表达式glob\_to\_regex()
    • 递归os.walk地通过当前目录,建立相对于您开始的级别的路径。如果路径与正则表达式匹配,则生成它。
  4. 如果 pat 不匹配"**",并且它是模式中的最后一个元素,则产生所有匹配的文件/目录glob.glob(os.path.join(curpath,pat[n]))

  5. 如果 pat 不匹配"**",并且它不是模式中的最后一个元素,那么对于每个目录,检查它是否匹配 (with glob) pat[n]。如果是这样,通过它向下递归,增加深度(所以它会看pat[n+1]

于 2008-10-02T16:07:32.973 回答
2

os.walk是你的朋友。查看 Python 手册 ( https://docs.python.org/2/library/os.html#os.walk ) 中的示例并尝试从中构建一些东西。

要将“ **/CVS/*”与您获得的文件名匹配,您可以执行以下操作:

def match(pattern, filename):
    if pattern.startswith("**"):
        return fnmatch.fnmatch(file, pattern[1:])
    else:
        return fnmatch.fnmatch(file, pattern)

fnmatch.fnmatch中,“*”匹配任何内容(包括斜线)。

于 2008-10-02T11:42:20.350 回答
1

“waf”构建系统源代码中有一个实现。 http://code.google.com/p/waf/source/browse/trunk/waflib/Node.py?r=10755#471 可能这应该包含在自己的库中吗?

于 2010-12-24T10:34:20.340 回答
0

是的。正如已经建议的那样,您最好的选择是使用“os.walk”。或者,也许可以围绕“ glob ”和“ fnmatch ”模块编写包装器。

于 2008-10-02T11:54:28.323 回答
0

os.walk是您最好的选择。我用 .svn 做了下面的例子,因为我很方便,而且效果很好:

import re

for (dirpath, dirnames, filenames) in os.walk("."):
    if re.search(r'\.svn$', dirpath):
        for file in filenames:
            print file
于 2008-10-02T14:47:57.440 回答