修改python中的符号链接

gar*_*h0p 30 python symlink

如何更改为符号链接以在Python中从一个文件指向另一个文件?os.symlink()函数似乎只能用于创建新的符号链接.

小智 27

如果您需要原子修改,则取消链接将不起作用.

更好的解决方案是创建一个新的临时符号链接,然后将其重命名为现有符号链接:

os.symlink(target, tmpLink)
os.rename(tmpLink, linkName)
Run Code Online (Sandbox Code Playgroud)

您可以检查以确保它也已正确更新:

if os.path.realpath(linkName) == target:
    # Symlink was updated
Run Code Online (Sandbox Code Playgroud)

根据os.rename的文档,可能无法在Windows中自动更改符号链接.在这种情况下,您只需删除并重新创建.

  • Python 3.3有`os.replace`,它可以代替`os.rename`在Posix和Windows系统上提供相同的行为. (9认同)

Rob*_*mer 23

一个尝试符号链接的小函数,如果由于现有文件而失败,它会删除它并再次链接.

import os, errno

def symlink_force(target, link_name):
    try:
        os.symlink(target, link_name)
    except OSError, e:
        if e.errno == errno.EEXIST:
            os.remove(link_name)
            os.symlink(target, link_name)
        else:
            raise e
Run Code Online (Sandbox Code Playgroud)


NPE*_*NPE 9

你可以os.unlink()先做,然后重新创建使用os.symlink()指向新目标.


Tom*_*ale 9

鉴于overwrite=True,此函数将安全地用符号链接覆盖现有文件。

它认识到竞争条件,这就是为什么它不短,但它是安全的。

import os, tempfile

def symlink(target, link_name, overwrite=False):
    '''
    Create a symbolic link named link_name pointing to target.
    If link_name exists then FileExistsError is raised, unless overwrite=True.
    When trying to overwrite a directory, IsADirectoryError is raised.
    '''

    if not overwrite:
        os.symlink(target, link_name)
        return

    # os.replace() may fail if files are on different filesystems
    link_dir = os.path.dirname(link_name)

    # Create link to target with temporary filename
    while True:
        temp_link_name = tempfile.mktemp(dir=link_dir)

        # os.* functions mimic as closely as possible system functions
        # The POSIX symlink() returns EEXIST if link_name already exists
        # https://pubs.opengroup.org/onlinepubs/9699919799/functions/symlink.html
        try:
            os.symlink(target, temp_link_name)
            break
        except FileExistsError:
            pass

    # Replace link_name with temp_link_name
    try:
        # Pre-empt os.replace on a directory with a nicer message
        if not os.path.islink(link_name) and os.path.isdir(link_name):
            raise IsADirectoryError(f"Cannot symlink over existing directory: '{link_name}'")
        os.replace(temp_link_name, link_name)
    except:
        if os.path.islink(temp_link_name):
            os.remove(temp_link_name)
        raise
Run Code Online (Sandbox Code Playgroud)

学徒注意事项:

  1. 如果该功能失败(例如计算机崩溃),则可能存在到目标的附加随机链接。

  2. 一个不太可能的竞争条件仍然存在:在随机命名的符号链接处创建的符号链接temp_link_name可以在替换之前被另一个进程修改link_name

我提出了一个python 问题来强调os.symlink()要求目标不存在的问题,有人建议我在邮件列表中提出我的建议python-ideas

感谢罗伯特Siemer的输入


cul*_*rón 6

我最近研究了这个问题,并发现,最好的办法确实是unlink,然后symlink.但是,如果您只需要修复损坏的链接,例如使用自动替换,那么您可以执行以下操作os.readlink:

for f in os.listdir(dir):
    path = os.path.join(dir, f)
    old_link = os.readlink(path)
    new_link = old_link.replace(before, after)
    os.unlink(path)
    os.symlink(new_link, path)
Run Code Online (Sandbox Code Playgroud)