129

I have a directory /a/b/c that has files and subdirectories. I need to copy the /a/b/c/* in the /x/y/z directory. What python methods can I use?

I tried shutil.copytree("a/b/c", "/x/y/z"), but python tries to create /x/y/z and raises an error "Directory exists".

Delgan
  • 18,571
  • 11
  • 90
  • 141
prosseek
  • 182,215
  • 215
  • 566
  • 871
  • 1
    Are you trying to move or copy the directory over? Your title says move, but your content says copy. Since these are two different things, it matters exactly which one you mean. – Carlos Feb 22 '13 at 22:37
  • Maybe give an example of before and after, to make it clearer what you want the effect to be, as well? – Xymostech Feb 22 '13 at 22:39
  • Thanks for your comment, I'll update the heading. It's copy, not move. – prosseek Feb 22 '13 at 22:39
  • 1
    Np. Also, like @Xymostech said, we're slightly unclear on the desired output. Do you want: /x/y/z/a/b/c or /x/y/z/c? Your use of `copytree` implies the former, but I just want to make sure. – Carlos Feb 22 '13 at 22:42
  • 1
    Could you simply delete any `/x/y/z/` directory first (`shutil.rmtree()`) and then do `copytree()`? – Eric O. Lebigot Feb 23 '13 at 04:54
  • @EOL: The issue is that I need to keep the existing files/directories in "/x/y/z". – prosseek Feb 23 '13 at 14:17
  • @prosseek: Do you need to do this at all depths? i.e. if you have `/a/b/c/t/u`, do you need to keep any `/x/y/z/t/v`? i.e. do you only need to create/overwrite, without deleting anything? – Eric O. Lebigot Feb 24 '13 at 09:21
  • Your problem was my solution. Thanks for your question. – AndreGraveler Oct 25 '19 at 03:57
  • 4
    This is no longer an issue as of Python 3.8 via the `copytree`'s `dirs_exist_ok=True` flag. See [doc](https://docs.python.org/3/library/shutil.html#shutil.copytree) – Jay May 28 '20 at 13:32

4 Answers4

228

I found this code working which is part of the standard library:

from distutils.dir_util import copy_tree

# copy subdirectory example
from_directory = "/a/b/c"
to_directory = "/x/y/z"

copy_tree(from_directory, to_directory)

Reference:

Martin Thoma
  • 124,992
  • 159
  • 614
  • 958
prosseek
  • 182,215
  • 215
  • 566
  • 871
  • 1
    An excellent solution, I suggest adding `update=1` to copy_tree() if that is what you need. – Hai Vu Feb 22 '13 at 22:59
  • 13
    Just bear in mind that copy_tree will fail if you call it twice for same set of args, and you've wiped the destination in the meantime. This is due to path caching in mkpath, see https://bugs.python.org/issue10948 – yacoob Dec 26 '16 at 00:15
  • What if I want to overwrite all existing files no matter what. Does this function overwrite existing files if update=0? – Dmitriy Jan 30 '17 at 17:48
  • 1
    funnily enough shutil.copy2 in a loop is much faster than copying the directory as a whole. – ikamen Jun 21 '18 at 14:58
  • 7
    If you repeatedly copy folders into the same destination, DO NOT USE this function. as @yacoob stated, this will fail in an unexpected way. Figuring it out gave me a headache. I am commenting again to increase visibility for others. – Martin Melka Jun 28 '18 at 14:39
  • 3
    FYI pathlib Path objects break dir_utils, which wants paths as text. – knowingpark Oct 24 '18 at 03:35
  • @yacoob does that mean we should not use copy_tree or this answer? what is the proper and safe way to do this? – Charlie Parker Jan 25 '22 at 23:00
  • is this a better way? at least it does not do weird stuff https://stackoverflow.com/a/50331781/1601580 `call(['cp', '-a', source, target])` – Charlie Parker Jan 25 '22 at 23:01
  • `DeprecationWarning: The distutils package is deprecated and slated for removal in Python 3.12` – v.oddou Apr 19 '22 at 09:19
  • This will get removed in python 3.12 – Mika C. May 26 '22 at 22:48
  • Ridiculous. I want to copy a directory and you have to import some non-obvious library then find it doesn't work in recent versions of Python. – Snowcrash Nov 11 '22 at 12:20
4

You can also use glob2 to recursively collect all paths (using ** subfolders wildcard) and then use shutil.copyfile, saving the paths

glob2 link: https://code.activestate.com/pypm/glob2/

ikudyk
  • 41
  • 1
1
from subprocess import call

def cp_dir(source, target):
    call(['cp', '-a', source, target]) # Linux

cp_dir('/a/b/c/', '/x/y/z/')

It works for me. Basically, it executes shell command cp.

Bowen Xu
  • 3,836
  • 1
  • 23
  • 25
-15

The python libs are obsolete with this function. I've done one that works correctly:

import os
import shutil

def copydirectorykut(src, dst):
    os.chdir(dst)
    list=os.listdir(src)
    nom= src+'.txt'
    fitx= open(nom, 'w')

    for item in list:
        fitx.write("%s\n" % item)

    fitx.close()

    f = open(nom,'r')
    for line in f.readlines():
        if "." in line:
            shutil.copy(src+'/'+line[:-1],dst+'/'+line[:-1])
        else:
            if not os.path.exists(dst+'/'+line[:-1]):
                os.makedirs(dst+'/'+line[:-1])
                copydirectorykut(src+'/'+line[:-1],dst+'/'+line[:-1])
            copydirectorykut(src+'/'+line[:-1],dst+'/'+line[:-1])
    f.close()
    os.remove(nom)
    os.chdir('..')
Evan Porter
  • 2,987
  • 3
  • 32
  • 44
kutenzo
  • 15