web-dev-qa-db-ja.com

Python)でシンボリックリンクをコピーする

ファイルsrcを宛先dstにコピーしたいのですが、srcがシンボリックリンクである場合は、ファイルの内容をコピーするのではなく、リンクを保持してください。コピーが実行された後、os.readlinksrcdstの両方に対して同じものを返す必要があります。

モジュールshutilにはcopyfilecopycopy2などのいくつかの関数がありますが、これらはすべてコピーされますcontents ofファイルであり、リンクは保持されません。 shutil.moveは、元のファイルを削除するという事実を除いて、正しい動作をします。

Pythonに、シンボリックリンクを保持しながらファイルコピーを実行する組み込みの方法はありますか?

24
davidg

Python 3 follow_symlinks

Python 3)では、shutilのほとんどのコピーメソッドがfollow_symlinks引数を学習しました。これは、選択された場合にシンボリックリンクを保持します。

例えば。 shutil.copyの場合:

shutil.copy(src, dest, follow_symlinks=False)

および ドキュメントによると

shutil.copy(src, dst, *, follow_symlinks=True)

ファイルsrcをファイルまたはディレクトリdstにコピーします。 srcとdstは文字列である必要があります。 dstがディレクトリを指定している場合、ファイルはsrcのベースファイル名を使用してdstにコピーされます。新しく作成されたファイルへのパスを返します。

follow_symlinksがfalseで、srcがシンボリックリンクの場合、dstはシンボリックリンクとして作成されます。 follow_symlinks`がtrueで、srcがシンボリックリンクの場合、dstはsrcが参照するファイルのコピーになります。

ただし、これには1つの問題があります。既存のファイルまたはシンボリックリンクを上書きしようとすると、次のように失敗します。

FileExistsError: [Errno 17] File exists: 'b' -> 'c'

正常に上書きされるfollow_symlinks=Trueとは異なります。

同じことがos.symlinkでも発生するため、代わりに次を使用することになりました。

#!/usr/bin/env python3

import shutil
import os

def copy(src, dst):
    if os.path.islink(src):
        if os.path.lexists(dst):
            os.unlink(dst)
        linkto = os.readlink(src)
        os.symlink(linkto, dst)
    else:
        shutil.copy(src, dst)

if __name__ == '__main__':
    os.symlink('c', 'b')
    os.symlink('b', 'a')
    copy('a', 'b')

    with open('c', 'w') as f:
        f.write('a')
    with open('d', 'w'):
        pass
    copy('c', 'd')
    copy('a', 'c')

Ubuntu 18.10でテスト済み、Python 3.6.7。

ただやる

def copy(src, dst):
    if os.path.islink(src):
        linkto = os.readlink(src)
        os.symlink(linkto, dst)
    else:
        shutil.copy(src,dst)

shutil.copytree は似たようなことをしますが、senderleが指摘したように、単一のファイルではなく、ディレクトリのみをコピーするのは慎重です。

44
Jochen Ritzel