使用否定的忽略模式进行Python复制目录树

8

我正在尝试使用Python复制文件/目录树。

使用copytree复制以foo结尾的所有内容是否可能?

有一个ignore_patterns模式函数,我可以给它一个否定的正则表达式吗?Python支持它们吗?

例如:

copytree(src,dest,False,ignore_pattern('!*.foo')) 其中!表示不是以foo结尾的任何内容。 谢谢。


'(.*.foo)'是正确的表达式,可以获取所有包含.foo的单词。(?!...)如在re模块文档[1]中所示,可用于否定表达式,但我无法使其工作... 1- http://docs.python.org/library/re.html - Diones
4个回答

8

shutil.copytree有一个名为ignore的关键字参数。可以将ignore设置为任何可调用对象。给定正在访问的目录和其内容列表,可调用对象应返回要忽略的目录和文件名序列。

例如:

import shutil
def ignored_files(adir,filenames):
    return [filename for filename in filenames if not filename.endswith('foo')]

shutil.copytree(source, destination, ignore=ignored_files)

3
我想指出的是,unutbu的答案除非嵌套目录也以“foo”结尾,否则不会遍历嵌套目录。相反,如果要执行 endswith 检查,则可能只想在 not os.path.isdir(filename) 的情况下执行。 - Josh
2
应该在 os.path.join(adir, filename) 上调用 os.path.isdir - Steve Rossiter

6

在unutbu的回答基础上进行改进。以下代码获取所有文件的列表,然后移除与"ignore_patterns"匹配的文件,并将其作为应该忽略的文件列表返回。也就是说,它采用了双重否定的方式,只复制您想要的文件。

import glob, os, shutil

def copyonly(dirpath, contents):
    return set(contents) - set(
        shutil.ignore_patterns('*.py', '*.el')(dirpath, contents),
        )

shutil.copytree(
    src='.',
    dst='temp/',
    ignore=copyonly,
    )
print glob.glob('temp/*')

0
def documentation(format):
    call(['make', format, '-C', DOC_SOURCE_DIR])

    if (os.path.exists(DOC_DIR)):
        shutil.rmtree(DOC_DIR)

    ignored = ['doctrees']
    shutil.copytree('{0}/build/'.format(DOC_SOURCE_DIR), DOC_DIR, ignore=shutil.ignore_patterns(*ignored))

0

@unutbu@johntellsall的基础上构建,这个解决方案也可以递归地工作。

def inverse_ignore_patterns(*patterns: str):
    def _inverse_ignore_patterns(path, names):
        ignored_names = set(names)
        for pattern in patterns:
            ignored_names -= set(fnmatch.filter(names, pattern))

        # Keep folders
        ignored_names -= {
            name for name in ignored_names
            if os.path.isdir(os.path.join(path, name))
        }
        return ignored_names

    return _inverse_ignore_patterns

一个缺点是,如果目录中没有匹配的文件,它将创建空目录。您可以轻松解决这个问题:

def rm_empty_folders(rootdir: str):
    for dirpath, dirnames, filenames in os.walk(rootdir, topdown=False):
        if not os.listdir(dirpath):
            os.rmdir(dirpath)

使用方法:

copytree(src, dest, False, inverse_ignore_patterns("*.foo"))
rm_empty_folders(dest)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接