如何在Python中检查文件是否为符号链接?

132
在Python中,是否有一个函数可以检查给定的文件/目录是否是符号链接?例如,对于下面的文件,我的包装函数应该返回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
3个回答

189
要确定一个目录条目是否是符号链接,请使用以下方法:

os.path.islink(path)

如果 path 引用的是一个 symbolic link 类型的目录条目,则返回 True。如果系统不支持 symbolic links,则始终返回 False。

例如,给定:
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

12
在Windows上,“快捷方式”显示为扩展名为“lnk”的文件,而os.islink('a_shortcut.lnk')返回False - Evgeni Sergeev
3
这是因为它们只是文件——可能是来自于 Windows 9x 时代的遗留问题,当时唯一的文件系统是 FAT/FAT32。请参阅此链接http://superuser.com/questions/347930/what-are-the-various-link-types-in-windows-how-do-i-create-them,了解在 NTFS 上支持的所有符号链接、硬链接和目录连接类型。尽管如此,我仍然认为 Python 不支持它们。 - jmc
11
islink()在Windows符号链接(即联接点)上无法工作。因此,这个答案仅适用于Unix系统。 - The Godfather
2
如果您需要Windows解决方案,请参考此https://dev59.com/2Ybca4cB1Zd3GeqPcfJB答案。 - The Godfather
2
@TheGodfather: 目录联接不是符号链接(IO_REPARSE_TAG_SYMLINK)。 - jfs
显示剩余3条评论

30

对于Python 3.4+,您可以使用Path类。

from pathlib import Path


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

使用 is_symlink() 方法时必须小心。只要命名对象是符号链接,它就会返回True,即使链接的目标不存在也是如此。

例如(Linux/Unix):

ln -s ../nonexistentfile flnk

然后,在您当前的目录中:

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

程序员必须决定他们真正想要什么。Python3 似乎重命名了很多类。阅读 Path 类的手册页面可能是值得的:https://docs.python.org/3/library/pathlib.html


1
这个程序可能只能找到有效的符号链接,可能无法识别那些是符号链接但已经损坏的文件。因此,如果你要过滤真实的文件或所有的符号链接(好的和坏的),请确保进行额外的检查。 - 2114L3
@2114L3 什么是有效但损坏的符号链接?通过对损坏的符号链接进行简单测试,似乎 is_symlink() 为 true,而 exists() 为 false,这正是我所期望的。你能提供你担忧的来源吗? - Jonathan H
2
@Sheljohn,请检查此答案的编辑,在我的评论之前,exists()不是答案的一部分。使用exists是我所指的额外检查。因为仅使用is_symlink是不够的,根据原始版本。 - 2114L3
在Windows上,这个功能对我来说无法正常工作:is_symlink 对不存在的文件返回 true(因此 exists() 也返回 true)。 - James Hirschorn
1
如何获取符号链接的真实路径 - CS QGB

6

为了不让这个话题变得冗长,但我在寻找符号链接并将它们转换为实际文件时被重定向到了这个页面,并在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")

3
你能解释一下这里发生了什么吗?看起来有点奇怪,因为似乎你在实际写回文件之前就删除(unlink)了它。这怎么可能呢?另外,最后一个 mkrealfile(...) 与它自己的函数处于同一级别... - not2qubit
似乎正在打开符号链接指向的文件(f_in),删除符号链接(但仍在读取指向的文件),然后在符号链接位置(f_out)写入/复制文件。查看链接,相关的源代码已更新为使用“with-as”惯用语,并使用二进制读/写(更适合复制文件),否则相同。 - JWCS
del f_out 不必做你认为的那样。最好直接调用 flush - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接