在Python中使用特殊的大小写处理实现递归复制

在Python中使用特殊的大小写处理实现递归复制,python,unix,filesystems,shutil,Python,Unix,Filesystems,Shutil,我想在Python中实现一个版本的cp-r,它以一种特殊的方式处理某些目录。如果您执行了mycp.py-r indir outdir,我希望将indir及其所有文件/子目录准确复制到outdir,但某些文件名除外。在Python中实现这一点的最可移植的方法是什么 示例:我有以下目录结构: dir1/ file1 dir2/ dir3/ specialdir/ myfile.bar file1是一个文件,specialdir是一个包含文件myfile.bar的目录。我

我想在Python中实现一个版本的
cp-r
,它以一种特殊的方式处理某些目录。如果您执行了
mycp.py-r indir outdir
,我希望将
indir
及其所有文件/子目录准确复制到
outdir
,但某些文件名除外。在Python中实现这一点的最可移植的方法是什么

示例:我有以下目录结构:

dir1/
  file1
  dir2/
    dir3/
  specialdir/
    myfile.bar
file1
是一个文件,
specialdir
是一个包含文件
myfile.bar
的目录。我想复制
dir1
及其所有内容,但要特别处理其中包含
*.bar
文件的目录。在这种情况下,只有
specialdir
符合标准。我想
mycopy
复制所有
dir1
,但用压缩版本的目录替换任何特殊目录。在上述示例中,这意味着按原样复制
dir1
,但将
specialdir
替换为
specialdir.zip
,该文件可能包含经过处理的
myfile.bar

我试着按照下面的建议做,但我不确定如何处理复制:

import os
import shutil

SPECIAL_DIRS = []

def is_special_dir(path, dirnames):
    """directories are special if they have .bar files"""
    special_dirs = []
    for d in dirnames:
        d = os.path.join(path, d)
        if os.path.isdir(d):
            files_in_d = os.listdir(d)
            for f in files_in_d:
                if f.endswith(".bar"):
                    # directory is special if it contains
                    # .bar files
                    special_dirs.append(d)
    SPECIAL_DIRS.extend(special_dirs)
    return special_dirs

def my_copy(indir, outdir):
    shutil.copytree(indir, outdir, ignore=is_special_dir)
    print "Found special dirs: ", SPECIAL_DIRS

# make a copy of dir1 but handle special directories
# differently
my_copy("dir1", "copy_dir1")
如果我尝试,它会正确检测特殊目录:

$ copy_test.py
Found special dirs:  ['dir1/dir2/specialdir']
我如何使其插入
specialdir
copy\u dir1
的正确对应位置?我希望
copy_dir1
(目标目录)的结构与
dir1
(源目录)完全相同,只是对包含
.bar
文件的目录进行了特殊处理。

听起来您希望使用忽略参数:

如果给出了ignore,则它必须是一个可调用的函数,它将接收由
copytree()
访问的目录作为其参数,以及由
os.listdir()
返回的目录内容列表。由于
copytree()
是递归调用的,因此将为复制的每个目录调用一次ignore callable。可调用项必须返回相对于当前目录的目录名和文件名序列(即第二个参数中的项目子集);这些名称将在复制过程中被忽略。”ignore_patterns()'可用于创建忽略基于全局样式模式的名称的可调用对象

因此,类似这样的方法应该有效:

def what_to_ignore(path,names):
    if is_special(path):
        # process names here returning any or all to ignore

shutil.copytree(indir,outdir,ignore=what_to_ignore)
编辑展开的问题和示例 这里有一个例子。简化的ignore函数仍然会创建一个空的特殊目录,但是在进行特殊的zip复制之前,很容易删除它。我还嵌套了这个特殊函数,因此
my_copy
可以多次使用,而无需使用全局变量。对用户来说,压缩是一项练习:

import fnmatch
import shutil
import os

def my_copy(indir, outdir):

    special = []

    def is_special_dir(path, names):
        """directories are special if they have .bar files"""
        if fnmatch.filter(names,'*.bar'):
            special.append(path)
            return names
        return []    

    shutil.copytree(indir, outdir, ignore=is_special_dir)
    print('Found special dirs:',special)

    for src in special:
        rel = os.path.relpath(src,indir)
        dst = os.path.join(outdir,rel)
        os.rmdir(dst)
        print('Zip "{}" to "{}.zip"'.format(src,dst))

my_copy('dir1','dira')
my_copy('dir1','dirb')
输出

Found special dirs: ['dir1\\specialdir']
Zip "dir1\specialdir" to "dira\specialdir.zip"
Found special dirs: ['dir1\\specialdir']
Zip "dir1\specialdir" to "dirb\specialdir.zip"

听起来很有用,但我的用例有点不同,我最初没有解释清楚。我不想跳过这组文件,但可能会对它们进行后处理,并将后处理版本复制到
outdir
。在这种情况下,我应该只使用
walk
?ignore函数可以做任何事情,包括收集文件名以进行后期处理。例如,如果函数返回一个空列表,它不会忽略任何内容,只会变成每个目录的回调。但是是否可以让回调在目标目录中插入一个文件(这是对输入目录中的文件进行某些后处理的结果),然后返回空的?否,没有办法指定要复制的额外文件,只有要忽略的原始目录中的文件,这就是您的问题所在。您可以在列表中收集特殊文件,然后对其进行后期处理并将其复制到目标目录,甚至可以在回调过程中自行处理并复制这些文件,并将已处理的文件作为忽略列表返回。谢谢我编辑了我的回答,以反映我编写您的建议的尝试