130

In Python, is there a function to check if a given file/directory is a symlink? For example, for the below files, my wrapper function should return 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
Milan
  • 1,743
  • 2
  • 13
  • 36
Bandicoot
  • 3,811
  • 7
  • 35
  • 39

3 Answers3

188

To determine if a directory entry is a symlink use this:

os.path.islink(path)

Return True if path refers to a directory entry that is a symbolic link. Always False if symbolic links are not supported.

For instance, given:

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
  • 138,105
  • 33
  • 200
  • 191
  • 11
    On Windows, _Shortcuts_ appear as files with extension `lnk`, and `os.islink('a_shortcut.lnk')` returns `False`. – Evgeni Sergeev Oct 16 '13 at 09:42
  • 3
    @EvgeniSergeev That's because they are just files - possibly a hangover from Windows 9x days when the only file system was FAT/FAT32. See this http://superuser.com/questions/347930/what-are-the-various-link-types-in-windows-how-do-i-create-them for all the types of symbolic/hard links and directory junctions supported on NTFS. That said, I still don't think Python supports them. – jmc Nov 06 '13 at 21:56
  • 11
    And islink() doesn't work for Windows symlinks, i.e. junctions. So the answer is applicable only for Unix. – The Godfather Mar 02 '15 at 09:14
  • 2
    Please refer to this http://stackoverflow.com/questions/27972776/having-trouble-implementing-a-readlink-function answer if you need Windows solution. – The Godfather May 21 '15 at 10:58
  • 2
    @TheGodfather: directory junction is not a symlink (`IO_REPARSE_TAG_SYMLINK`). – jfs Nov 04 '16 at 10:08
  • @J.F.Sebastian it doesn't matter, usually when one says "I need to check whether it is a symlink or not" - no one cares about concrete symlinks types. Symlinks\junctions\whatever - all of those are symlinks and I need to be able to check all of those. – The Godfather Nov 06 '16 at 05:21
  • 1
    @TheGodfather you said: *"islink() doesn't work for Windows symlinks, i.e., junctions"* that creates an impression that all symlinks are junctions (wrong) and therefore `islink()` does not work with symlinks at all (wrong). I don't know whether `islink()` will be extended or not, to include junctions, mounted folders, RSS, etc. If you want `islink()` to mean `is_reparse_point()` (with all that it entails); say so. Here's a [related question (in Russian) with links for more information](http://ru.stackoverflow.com/q/586134/23044). – jfs Nov 06 '16 at 11:30
  • 1
    Keep in mind that if you add a trailing slash to a directory that's a symlink, `islink` will return False. For example, `os.path.islink("./mydir") = True` but `os.path.islink("./mydir/") = False`. – Nathan F. Jan 18 '21 at 19:08
26

For python3.4+, you can use the Path class

from pathlib import Path


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

You have to be careful when using the is_symlink() method. It will return True as long as the the named object is a symlink, even if the target of the link is non-existent.

For example (Linux/Unix):

ln -s ../nonexistentfile flnk

Then, in your current directory:

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

The programmer has to decide what they really want. Python3 seems to have renamed a lots of classes. It might be worthwhile to read the manual page for the Path class: https://docs.python.org/3/library/pathlib.html

Karan Shah
  • 417
  • 6
  • 21
Kemin Zhou
  • 6,264
  • 2
  • 48
  • 56
  • 1
    this MAY only finds valid symlink, this MAY not identify a file that is a symlink but is broken. so if you are filtering for real files or all symlinks (good and bad) then ensure you do additional checks – 2114L3 Sep 25 '16 at 12:31
  • @2114L3 What does a valid but broken symlink mean? From simple testing with a broken symlink, it seems that `is_symlink()` is true, and `exists()` is false, which is what I would expect. Can you give a source for your concerns? – Jonathan H Mar 05 '18 at 02:07
  • 2
    @Sheljohn check the edits on this answer, before my comment exists() was not a part of the answer. using exists is a additional check of which i meant. as using is_symlink alone is not enough as per original version. – 2114L3 Apr 02 '18 at 00:56
  • On Windows this is not working correctly for me: `is_symlink` is returning `true` for nonexistent files (so `exists()` also returns `true`). – James Hirschorn Aug 19 '19 at 17:01
  • how to get symlink real path – CS QGB May 04 '23 at 14:07
5

Without the intention to bloat this topic, but I was redirected to this page as I was looking for symlink's to find them and convert them to real files and found this script within the python tools library.

#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
  • 23,311
  • 18
  • 141
  • 164
  • 2
    Can you explain what is happening here? It look kind of weird as it seem that your're removing (unlink) the file *before* actually writing it back. How can this be? Also the last `mkrealfile(...)` is on the same level as it's own function... – not2qubit Oct 18 '20 at 19:48
  • It seems to be opening up (f_in) the file pointed to by the symlink, deleting the symlink (but the file pointed to is still being read), then at the location where the symlink was (f_out), writing / copying the file over. Looking at the link, the src code in question has been updated with the `with-as` idiom and uses binary read/write (better for copying files), otherwise same. – JWCS Feb 01 '22 at 16:37