Verifique se o arquivo é um link simbólico em python

91

Em python, existe uma função para verificar se um determinado arquivo / diretório é um link simbólico? Por exemplo, para os arquivos abaixo, minha função de wrapper deve retornar 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
fonte

Respostas:

136

Para determinar se uma entrada de diretório é um link simbólico, use isto:

os.path.islink (caminho)

Retorna True se o caminho se refere a uma entrada de diretório que é um link simbólico. Sempre False se links simbólicos não forem suportados.

Por exemplo, 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
fonte
7
No Windows, os atalhos aparecem como arquivos com extensão lnke os.islink('a_shortcut.lnk')retornam False.
Evgeni Sergeev
1
@EvgeniSergeev Isso porque eles são apenas arquivos - possivelmente uma lembrança do Windows 9x dias, quando o único sistema de arquivos era FAT / FAT32. Consulte superuser.com/questions/347930/… para todos os tipos de links simbólicos / físicos e junções de diretório com suporte em NTFS. Dito isso, ainda não acho que Python os suporte.
jmc
9
E islink () não funciona para links simbólicos do Windows, ou seja, junções. Portanto, a resposta é aplicável apenas para Unix.
The Godfather
2
Consulte esta resposta stackoverflow.com/questions/27972776/… se você precisar da solução do Windows.
The Godfather
1
@TheGodfather: junção de diretório não é um link simbólico ( IO_REPARSE_TAG_SYMLINK).
jfs
11

Para python 3.4 e superior, você pode usar a classe Path

from pathlib import Path


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

Você deve ter cuidado ao usar o método is_symlink (). Ele retornará True mesmo que o destino do link não exista, desde que o objeto nomeado seja um link simbólico. Por exemplo (Linux / Unix):

ln -s ../nonexistentfile flnk

Então, em seu diretório atual acione o python

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

O programador tem que decidir o que ele realmente quer. O Python 3 parece ter renomeado várias classes. Pode valer a pena ler a página de manual da classe Path: https://docs.python.org/3/library/pathlib.html

Kemin Zhou
fonte
isso PODE encontrar apenas um link simbólico válido, isso PODE não identificar um arquivo que é um link simbólico, mas está quebrado. portanto, se você estiver filtrando arquivos reais ou todos os links simbólicos (bons e ruins), certifique-se de fazer verificações adicionais
2114L3
@ 2114L3 O que significa um link simbólico válido, mas quebrado? A partir de um teste simples com um link simbólico quebrado, parece que is_symlink()é verdade e exists()é falso, que é o que eu esperava. Você pode fornecer uma fonte de suas preocupações?
Jonathan H
1
@Sheljohn verifique as edições nesta resposta, antes que meu comentário exista () não fazia parte da resposta. usar existe é uma verificação adicional de que eu quis dizer. como usar is_symlink sozinho não é suficiente para a versão original.
2114L3,
No Windows, isso não está funcionando corretamente para mim: is_symlinkestá retornando truepara arquivos inexistentes (então exists()também retorna true).
James Hirschorn
3

Sem a intenção de sobrecarregar este tópico, mas fui redirecionado para esta página enquanto procurava links simbólicos para encontrá-los e convertê-los em arquivos reais e encontrei este script na biblioteca de ferramentas do 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")
user1767754
fonte