Sprawdź, czy plik jest dowiązaniem symbolicznym w Pythonie

98

Czy w Pythonie jest funkcja sprawdzająca, czy dany plik / katalog jest dowiązaniem symbolicznym? Na przykład dla poniższych plików powinna zwrócić moja funkcja opakowania 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
źródło

Odpowiedzi:

142

Aby określić, czy pozycja katalogu jest dowiązaniem symbolicznym, użyj tego:

os.path.islink (ścieżka)

Zwróć True, jeśli ścieżka odnosi się do pozycji katalogu, która jest dowiązaniem symbolicznym. Zawsze Fałsz, jeśli dowiązania symboliczne nie są obsługiwane.

Na przykład, biorąc pod uwagę:

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
źródło
8
W systemie Windows skróty pojawiają się jako pliki z rozszerzeniem lnki os.islink('a_shortcut.lnk')zwrotami False.
Evgeni Sergeev
1
@EvgeniSergeev To dlatego, że są to tylko pliki - prawdopodobnie kac z Windows 9x dni, kiedy jedynym systemem plików był FAT / FAT32. Zobacz ten superuser.com/questions/347930/ ... dla wszystkich typów symbolicznych / twardych dowiązań i połączeń katalogów obsługiwanych w systemie plików NTFS. To powiedziawszy, nadal nie sądzę, aby Python je obsługiwał.
jmc
10
I islink () nie działa z dowiązaniami symbolicznymi Windows, tj. Połączeniami. Zatem odpowiedź dotyczy tylko Uniksa.
Ojciec chrzestny
2
Jeśli potrzebujesz rozwiązania dla systemu Windows, zapoznaj się z tą stackoverflow.com/questions/27972776/ ... odpowiedzią.
Ojciec chrzestny
1
@TheGodfather: przyłączenie katalogu nie jest dowiązaniem symbolicznym ( IO_REPARSE_TAG_SYMLINK).
jfs
13

W przypadku języka Python 3.4 i nowszych można użyć klasy Path

from pathlib import Path


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

Musisz być ostrożny używając metody is_symlink (). Zwróci True, nawet jeśli cel łącza nie istnieje, o ile nazwany obiekt jest dowiązaniem symbolicznym. Na przykład (Linux / Unix):

ln -s ../nonexistentfile flnk

Następnie w bieżącym katalogu uruchom Pythona

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

Programista musi zdecydować, czego naprawdę chce. Wygląda na to, że Python 3 zmienił nazwy wielu klas. Warto przeczytać stronę podręcznika dla klasy Path: https://docs.python.org/3/library/pathlib.html

Kemin Zhou
źródło
to MOŻE znaleźć tylko prawidłowe dowiązanie symboliczne, MOŻE nie zidentyfikować pliku, który jest dowiązaniem symbolicznym, ale jest uszkodzony. więc jeśli filtrujesz w poszukiwaniu prawdziwych plików lub wszystkich linków symbolicznych (dobrych i złych), upewnij się, że wykonasz dodatkowe kontrole
2114L3
@ 2114L3 Co oznacza prawidłowe, ale uszkodzone łącze symboliczne? Po prostym testowaniu z uszkodzonym dowiązaniem symbolicznym wydaje się, że is_symlink()to prawda i exists()fałsz, czego bym się spodziewał. Czy możesz podać źródło swoich obaw?
Jonathan H
1
@Sheljohn sprawdź zmiany w tej odpowiedzi, zanim mój komentarz istnieje () nie był częścią odpowiedzi. użycie istnieje jest dodatkowym sprawdzeniem, o którym miałem na myśli. ponieważ samo użycie is_symlink nie wystarczy, jak w oryginalnej wersji.
2114L3
W systemie Windows nie działa to poprawnie dla mnie: is_symlinkzwraca truenieistniejące pliki (więc exists()również zwraca true).
James Hirschorn
3

Bez zamiaru nadużywania tego tematu, ale zostałem przekierowany na tę stronę, ponieważ szukałem linków symbolicznych, aby je znaleźć i przekonwertować na prawdziwe pliki, i znalazłem ten skrypt w bibliotece narzędzi Pythona.

#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
źródło
Czy możesz wyjaśnić, co się tutaj dzieje? Wygląda to trochę dziwnie, ponieważ wydaje się, że usuwasz (odłączasz) plik przed jego ponownym zapisaniem. Jak to może być? Również ostatni mkrealfile(...)jest na tym samym poziomie, co jego własna funkcja ...
not2qubit