83

when i give ls -l /etc/fonts/conf.d/70-yes-bitmaps.conf

lrwxrwxrwx <snip> /etc/fonts/conf.d/70-yes-bitmaps.conf -> ../conf.avail/70-yes-bitmaps.conf

so for a symbolic link or soft link, how to find the target file's full(absolute path) in python,

If i use

os.readlink('/etc/fonts/conf.d/70-yes-bitmaps.conf')

it outputs

../conf.avail/70-yes-bitmaps.conf

but i need the absolute path not the relative path, so my desired output must be,

/etc/fonts/conf.avail/70-yes-bitmaps.conf

how to replace the .. with the actual full path of the parent directory of the symbolic link or soft link file.

duhhunjonn
  • 44,855
  • 11
  • 28
  • 15
  • `os.readlink` should work on ubuntu/windows, python 3.5. Just tested it: https://stackoverflow.com/a/49590179/4752883 – alpha_989 Mar 31 '18 at 16:50

6 Answers6

149
os.path.realpath(path)

os.path.realpath returns the canonical path of the specified filename, eliminating any symbolic links encountered in the path.

unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
  • 5
    os.path.realpath doesn't eliminate symbolic links in Python 3.2 under Windows 7. (A bug?) – Dave Burton Mar 09 '12 at 14:05
  • 2
    Hmmm... I see that this has been an open bug for 1.5 years: http://bugs.python.org/issue9949 – Dave Burton Mar 09 '12 at 14:23
  • 2
    Yup getting this same problem, 3 years later :c – Cobertos Aug 22 '15 at 04:16
  • 2
    in Python3, if you're using a `Path` object, you can do the same thing by doing `path.resolve()` – rogueleaderr Mar 20 '18 at 19:57
  • If `C:\\Users\\PP` is a symlink to another directory, in Windows 10 using python 3.5, `os.path.realpath("C:\\Users\PP")`basically returns the symlink path, not the real path. – alpha_989 Mar 31 '18 at 16:45
  • 2
    The Windows issue is fixed in Python 3.8: "Changed in version 3.8: Symbolic links and junctions are now resolved on Windows." – Diego Apr 17 '20 at 21:01
  • 1
    Note that this depends on your current directory. Docs [say](https://docs.python.org/3/library/os.path.html#os.path.abspath) "On most platforms, this is equivalent to calling the function `normpath()` as follows: `normpath(join(os.getcwd(), path))`". – famzah Feb 10 '21 at 16:01
  • This assumes that your working directory is at the file with the symlink – Nasif Imtiaz Ohi Mar 07 '22 at 18:42
  • os.path.realpath and ls -l have different results on mount driver – CS QGB Apr 06 '22 at 07:11
17

As unutbu says, os.path.realpath(path) should be the right answer, returning the canonical path of the specified filename, resolving any symbolic links to their targets. But it's broken under Windows.

I've created a patch for Python 3.2 to fix this bug, and uploaded it to:

http://bugs.python.org/issue9949

It fixes the realpath() function in Python32\Lib\ntpath.py

I've also put it on my server, here:

http://www.burtonsys.com/ntpath_fix_issue9949.zip

Unfortunately, the bug is present in Python 2.x, too, and I know of no fix for it there.

Marcin Orlowski
  • 72,056
  • 11
  • 123
  • 141
Dave Burton
  • 2,960
  • 29
  • 19
12

http://docs.python.org/library/os.path.html#os.path.abspath

also joinpath() and normpath(), depending on whether you're in the current working directory, or you're working with things elsewhere. normpath() might be more direct for you.

Specifically:

os.path.normpath( 
  os.path.join( 
    os.path.dirname( '/etc/fonts/conf.d/70-yes-bitmaps.conf' ), 
    os.readlink('/etc/fonts/conf.d/70-yes-bitmaps.conf') 
  ) 
)
pppery
  • 3,731
  • 22
  • 33
  • 46
eruciform
  • 7,680
  • 1
  • 35
  • 47
  • 2
    Be warned though: should you pass a path which is not a symlink to readlink it will get angry and give the following exception: `OSError: [Errno 22] Invalid argument: 'your-path'` – Diego Jan 23 '15 at 10:33
8

I recommend using pathlib library for filesystem operations.

import pathlib

x = pathlib.Path('lol/lol/path')
x.resolve()

Documentation for Path.resolve(strict=False): make the path absolute, resolving any symlinks. A new path object is returned.

Luke Moore
  • 685
  • 5
  • 7
Alex
  • 1,221
  • 2
  • 26
  • 42
1

On windows 10, python 3.5, os.readlink("C:\\Users\PP") where "C:\Users\PP" is a symbolic link (not a junction link) works.

It returns the absolute path to the directory.

This works on Ubuntu 16.04, python 3.5 as well.

alpha_989
  • 4,882
  • 2
  • 37
  • 48
0

The documentation says to use os.path.join():

The result may be either an absolute or relative pathname; if it is relative, it may be converted to an absolute pathname using os.path.join(os.path.dirname(path), result).

Don Kirkby
  • 53,582
  • 27
  • 205
  • 286
  • `os.path.abspath` ? – dmitry_romanov Jul 12 '19 at 05:43
  • 1
    Not needed, @dmitry_romanov. If you just called `os.path.abspath(result)`, it wouldn't know where the path should start. That's why you need to pass in `path`. If `result` is already an absolute path, then `join` is smart. From the docs: "If a component is an absolute path, all previous components are thrown away and joining continues from the absolute path component." – Don Kirkby Jul 12 '19 at 18:57