2

我想cp -r在 Python 中实现一个以特殊方式处理某些目录的版本。如果您这样做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按原样复制,但替换specialdirspecialdir.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_dir1?我希望copy_dir1(目标目录)具有与(源目录)完全相同的结构,dir1除了对包含.bar文件的目录进行特殊处理。

4

1 回答 1

3

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

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

所以这样的事情应该有效:

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)

编辑扩展问题和示例

这是一个例子。简化的忽略功能仍然会创建一个空的特殊目录,但在进行特殊 zip 复制之前很容易删除。我还嵌套了特殊函数,因此my_copy可以多次使用而不依赖于使用全局变量。执行 zip 对用户来说是一项练习:

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"
于 2013-02-03T03:10:21.793 回答