2

cp -r特定のディレクトリを特別な方法で処理するバージョンのPythonを実装したいと思います。そうした場合、特定のファイル名を除いて、そのすべてのファイル/サブディレクトリを正確ににコピーしmycp.py -r indir outdirたいと思います。Pythonでこれを行うための最も移植性の高い方法は何ですか?indiroutdir

例:私はこのディレクトリ構造を持っています:

dir1/
  file1
  dir2/
    dir3/
  specialdir/
    myfile.bar

file1はファイルであり、はファイルspecialdirを含むディレクトリですmyfile.bardir1とそのすべての内容をコピーしたいのですが*.bar、ファイルを含む特別なディレクトリを処理します。この場合specialdir、基準を満たすだけです。mycopyすべてをコピーしたいのですdir1が、特別なディレクトリをzip形式で置き換えます。上記の例では、そのままコピーすることを意味し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

ignoreパラメータを使用してshutil.copytreeが必要なようです。

ignoreが指定された場合、 がアクセスしているディレクトリcopytree()と、 が返すその内容のリストを引数として受け取る callable でなければなりませんos.listdir()copytree()は再帰的に呼び出されるため、ignore callableは、コピーされるディレクトリごとに 1 回呼び出されます。callable は、現在のディレクトリに関連する一連のディレクトリ名とファイル名 (つまり、2 番目の引数のアイテムのサブセット) を返さなければなりません。これらの名前は、コピー プロセスでは無視されます。'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 に答える