Как получить символическую ссылку в Python?

Используя Python, мне нужно проверить, правильны ли сотни символических ссылок и воссоздать их, когда нет. Теперь я должен сравнивать реальные пути того, что я хочу, и то, что у меня есть, но он медленный, потому что он над NFS с автомонтированием.

В противном случае я буду запускать подпроцесс с помощью команды ls -l и работать в списке возвращаемых строк. Я бы предпочел лучшее решение, используя библиотеку Python...

Edit1: У меня: link_name -> link_target, а затем link_target -> a_real_file. Мне нужно извлечь link_target из link_name, а не a_real_file. Мне все равно, нет ли реального файла.

Правка2: Возможно, я не правильно выразился. То, что я подразумеваю под правильной символической ссылкой, - это "ссылка, которая указывает на предопределенный путь, даже если он не существует". Поэтому мне нужно проверить, что:

link_name_1 -> target_1
link_name_2 -> target_2

Вот почему мне нужно извлекать цели, а не реальные пути. Затем я сравниваю их со ссылкой (словарем). Поэтому мой вопрос: как извлечь целевой путь?

Ответ 1

Проблема с os.readlink() заключается в том, что он разрешит только один шаг ссылки. Мы можем иметь ситуацию, когда A ссылается на другую ссылку B, а ссылка B висит.

$ ln -s /tmp/example/notexist /tmp/example/B
$ ln -s /tmp/example/B /tmp/example/A
$ ls -l /tmp/example
A -> /tmp/example/B
B -> /tmp/example/notexist

Теперь в Python os.readlink дает вам первую цель.

>>> import os
>>> os.readlink('A')
'/tmp/example/B'

Но в большинстве случаев я предполагаю, что нас интересует разрешенный путь. Так что pathlib может помочь здесь:

>>> from pathlib import Path
>>> Path('A').resolve()
PosixPath('/tmp/example/notexist')

Для более старых версий Python:

>>> os.path.realpath('A')
'/tmp/example/notexist'

Ответ 2

Вам нужно посмотреть на os.readlink().

Ответ 3

Чтобы определить, является ли запись каталога символьной ссылкой, используйте это:

os.path.islink(путь)

Возвращает True, если путь относится к записи каталога, которая является символической ссылкой. Всегда False, если символические ссылки не поддерживаются.

Ответ 4

Чтобы определить, не сломана ли ссылка, вы можете, os.walk и проверить os.path.exists(path), который вернет False для неработающей ссылки. Затем вы можете использовать os.path.realpath(path), чтобы узнать, на что должна указывать ссылка.
Что-то вроде (не проверено):

for root, dirs, files in os.walk('<path>'):
    for file in files:
         f = os.join(root, file)
         if os.path.islink(f) and not os.path.exists(f):
             print("Broken: {} -> {}".format(f, os.path.realpath(f)))