web-dev-qa-db-fra.com

Modification d'un lien symbolique dans python

Comment changer un symbole symbolique vers un point d'un fichier à un autre à Python?

Les os.symlink fonction semble seulement fonctionner pour créer de nouveaux symboles.

33
meteoritepanama

Un peu de fonction pour Python2 qui essaie de symboliser et s'il échoue à cause d'un fichier existant, il l'enlève et relie à nouveau. Chèque Réponse de Tom Hale pour une solution à jour.

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
23
Robert Siemer

Vous pouvez os.unlink() C'est en premier, puis recréez-la à l'aide de os.symlink() pour pointer vers la nouvelle cible.

9
NPE

J'ai récemment étudié cette question et j'ai découvert que le meilleur moyen est en effet de unlink, puis symlink. Mais si vous avez besoin de corriger des liens brisés, par exemple avec auto-remplacement, vous pouvez le faire 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)
6
culebrón

Compte tenu de overwrite=True, Cette fonction remplacera en toute sécurité un fichier existant avec un symbole symbolique.

C'est conscient des conditions de race, c'est pourquoi ce n'est pas court, mais c'est sûr.

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, linkname)
        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 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

Notes pour les pédants:

  1. Si la fonction échoue (par exemple, un boîtier d'ordinateur), un lien aléatoire supplémentaire à la cible pourrait exister.

  2. Une condition de race improbable reste toujours: le symbole symbolique créé à la nommée de manière aléatoire temp_link_name Pourrait être modifié par un autre processus avant de remplacer link_name.

J'ai soulevé un problème de python pour mettre en évidence les problèmes de os.symlink() exiger que la cible n'existe pas, où on m'a conseillé d'augmenter ma suggestion sur le python-ideas Liste de diffusion

Crédit à Entrée de Robert Siemer .

3
Tom Hale

N'oubliez pas d'ajouter une commande d'élevage dans le cas où e.errno! = Errno.eexist Vous ne voulez pas masquer une erreur alors:

if e.errno == errno.EEXIST:
     os.remove(link_name)
     os.symlink(target, link_name)
else:
    raise
1
crivera

Une solution rapide et facile:

while True:
     try:
         os.symlink(target, link_name)
         break
     except FileExistsError:
         os.remove(link_name)

Cependant, cela a une condition de course lors du remplacement d'un symbolique qui devrait toujours existe, par exemple:

 /lib/critical.so -> /lib/critical.so.1.2

Lors de la mise à niveau:

 my_symlink('/lib/critical.so.2.0', '/lib/critical.so')

Il y a un point à temps quand /lib/critical.so n'existe pas.

Cette réponse Évite la condition de course.

0
Tom Hale