Compruebe si el archivo es un enlace simbólico en Python

91

En Python, ¿hay una función para verificar si un archivo / directorio determinado es un enlace simbólico? Por ejemplo, para los archivos a continuación, mi función contenedora debería regresar True.

# ls -l
total 0
lrwxrwxrwx 1 root root 8 2012-06-16 18:58 dir -> ../temp/
lrwxrwxrwx 1 root root 6 2012-06-16 18:55 link -> ../log
Bandicoot
fuente

Respuestas:

136

Para determinar si una entrada de directorio es un enlace simbólico, use esto:

os.path.islink (ruta)

Devuelve True si la ruta se refiere a una entrada de directorio que es un enlace simbólico. Siempre falso si no se admiten enlaces simbólicos.

Por ejemplo, dado:

drwxr-xr-x   2 root root  4096 2011-11-10 08:14 bin/
drwxrwxrwx   1 root root    57 2011-07-10 05:11 initrd.img -> boot/initrd.img-2..

>>> import os.path
>>> os.path.islink('initrd.img')
True
>>> os.path.islink('bin')
False
Levon
fuente
7
En Windows, los accesos directos aparecen como archivos con extensión lnky os.islink('a_shortcut.lnk')regresan False.
Evgeni Sergeev
1
@EvgeniSergeev Eso es porque son solo archivos, posiblemente una resaca de los días de Windows 9x cuando el único sistema de archivos era FAT / FAT32. Consulte este superusuario.com/questions/347930/… para conocer todos los tipos de enlaces simbólicos / duros y uniones de directorio compatibles con NTFS. Dicho esto, todavía no creo que Python los admita.
jmc
9
Y islink () no funciona para enlaces simbólicos de Windows, es decir, uniones. Entonces, la respuesta es aplicable solo para Unix.
El Padrino
2
Consulte esta respuesta stackoverflow.com/questions/27972776/… si necesita una solución de Windows.
El Padrino
1
@TheGodfather: la unión de directorio no es un enlace simbólico ( IO_REPARSE_TAG_SYMLINK).
jfs
11

Para Python 3.4 y versiones posteriores, puede usar la clase Path

from pathlib import Path


# rpd is a symbolic link
>>> Path('rdp').is_symlink()
True
>>> Path('README').is_symlink()
False

Debe tener cuidado al usar el método is_symlink (). Devolverá True incluso si el destino del enlace no existe, siempre que el objeto nombrado sea un enlace simbólico. Por ejemplo (Linux / Unix):

ln -s ../nonexistentfile flnk

Luego, en su directorio actual, inicie Python

>>> from pathlib import Path
>>> Path('flnk').is_symlink()
True
>>> Path('flnk').exists()
False

El programador tiene que decidir lo que realmente quiere. Python 3 parece haber cambiado el nombre de muchas clases. Puede que valga la pena leer la página del manual de la clase Path: https://docs.python.org/3/library/pathlib.html

Kemin Zhou
fuente
esto PUEDE solo encuentra un enlace simbólico válido, esto PUEDE no identificar un archivo que es un enlace simbólico pero está roto. por lo tanto, si está filtrando archivos reales o todos los enlaces simbólicos (buenos y malos), asegúrese de realizar comprobaciones adicionales
2114L3
@ 2114L3 ¿Qué significa un enlace simbólico válido pero roto? A partir de una simple prueba con un enlace simbólico roto, parece que is_symlink()es cierto y exists()es falso, que es lo que esperaría. ¿Puede dar una fuente de sus preocupaciones?
Jonathan H
1
@Sheljohn verifique las ediciones en esta respuesta, antes de que mi comentario exista () no fue parte de la respuesta. el uso de existe es una comprobación adicional de lo que quise decir. ya que usar is_symlink solo no es suficiente según la versión original.
2114L3
En Windows, esto no funciona correctamente para mí: is_symlinkestá regresando truepara archivos inexistentes (por lo que exists()también regresa true).
James Hirschorn
3

Sin la intención de inflar este tema, pero fui redirigido a esta página porque estaba buscando enlaces simbólicos para encontrarlos y convertirlos en archivos reales y encontré este script dentro de la biblioteca de herramientas de Python.

#Source https://github.com/python/cpython/blob/master/Tools/scripts/mkreal.py


import sys
import os
from stat import *

BUFSIZE = 32*1024

def mkrealfile(name):
    st = os.stat(name) # Get the mode
    mode = S_IMODE(st[ST_MODE])
    linkto = os.readlink(name) # Make sure again it's a symlink
    f_in = open(name, 'r') # This ensures it's a file
    os.unlink(name)
    f_out = open(name, 'w')
    while 1:
        buf = f_in.read(BUFSIZE)
        if not buf: break
        f_out.write(buf)
    del f_out # Flush data to disk before changing mode
    os.chmod(name, mode)

    mkrealfile("/Users/test/mysymlink")
usuario1767754
fuente