17

What I basically would like to do is cp -Rl dir1 dir2. But as I understand it, python only provides shutils.copytree(src,dst) which actually copies the files, but has no possibility of hardlinking the files instead.

I know that I could invoke the cp command using the subprocess module, but I'd rather like to find a cleaner (pythonic) way to do so.

So is there an easy way to do so or do I have to implement it myself recursing through the directories?

devsnd
  • 7,382
  • 3
  • 42
  • 50
  • The directory traversal is pretty easy to do, so why not try it? – Blender May 28 '12 at 03:09
  • 4
    It is not about trying or not trying: The question rather wants to say "I can't imagine that this hasn't been done before hundreds of times and therefore must be available in module xy". Reinventing the wheel all the time just doesn't seem right. – devsnd May 28 '12 at 14:55

2 Answers2

26

You just have to call os.system("cp -Rl dir1 dir2"), no need hand write your own function.

Edited: Since you want do this in python.

You are right: It's available in module shutil:

shutil.copytree(src, dst, copy_function=os.link)
not2qubit
  • 14,531
  • 8
  • 95
  • 135
Kabie
  • 10,489
  • 1
  • 38
  • 45
  • 1
    As I stated, I rather don't want to use the subprocess module. That also means that I wouldn't want to use the `os.system` call, as it gives me even less controll than `subprocess`. Especially because `os.system` might fail silently. – devsnd May 28 '12 at 14:29
  • 1
    @twall: Note this is Python 3 only. In Python 2, you might modify the example code: http://docs.python.org/library/shutil.html#copytree-example – Kabie May 29 '12 at 01:16
  • 1
    Ah great! I have now already used the example of Damian Ayers and modified it to my needs, but this is actually the solution I thought of. (I should have looked at the shutil sources before...) Thank you! – devsnd May 29 '12 at 11:29
  • I know this is many years old now, but I just want to say that the "os.system" suggestion is a not a great one. `cp -l' is not standard. GNU cp and FreeBSD cp do both support it, but it is not required and therefore not a good idea to use in any kind of script. – Roflcopter4 Apr 14 '18 at 21:57
  • It's not at all clear from the Python docs if `copy_function=os.link` actually exists, or need to be created artificially. (See examples in the linked docs.) If it does, then also `os.symlink` should be possible. – not2qubit Oct 19 '20 at 20:35
  • Generally speaking, `os.system` is an awful solution in Python and should be avoided. Thanks for the shutil version. – sauerburger Mar 03 '23 at 09:13
7

Here's a pure python hardcopy function. Should work the same as cp -Rl src dst

import os
from os.path import join, abspath

def hardcopy(src, dst):
    working_dir = os.getcwd()
    dest = abspath(dst)
    os.mkdir(dst)
    os.chdir(src)
    for root, dirs, files in os.walk('.'):
        curdest = join(dst, root)
        for d in dirs:
            os.mkdir(join(curdst, d))
        for f in files:
            fromfile = join(root, f)
            to = join(curdst, f)
            os.link(fromfile, to)
    os.chdir(working_dir)
Damien Ayers
  • 1,551
  • 10
  • 17
  • Sorry for unaccepting your answer, but the other one really is the right answer to that question, even though your answer also solves the problem. Thanks again. – devsnd May 29 '12 at 11:32
  • No worries. I haven't looked at python 3 much, but if that's what you're on it's a far neater solution. :) – Damien Ayers May 29 '12 at 12:28