Skip to content Skip to sidebar Skip to footer

Find Broken Symlinks With Python

If I call os.stat() on a broken symlink, python throws an OSError exception. This makes it useful for finding them. However, there are a few other reasons that os.stat() might thro

Solution 1:

A common Python saying is that it's easier to ask forgiveness than permission. While I'm not a fan of this statement in real life, it does apply in a lot of cases. Usually you want to avoid code that chains two system calls on the same file, because you never know what will happen to the file in between your two calls in your code.

A typical mistake is to write something like:

ifos.path.exists(path):
    os.unlink(path)

The second call (os.unlink) may fail if something else deleted it after your if test, raise an Exception, and stop the rest of your function from executing. (You might think this doesn't happen in real life, but we just fished another bug like that out of our codebase last week - and it was the kind of bug that left a few programmers scratching their head and claiming 'Heisenbug' for the last few months)

So, in your particular case, I would probably do:

try:
    os.stat(path)
except OSError, e:
    if e.errno == errno.ENOENT:
        print'path %s does not exist or is a broken symlink' % pathelse:
        raise e

The annoyance here is that stat returns the same error code for a symlink that just isn't there and a broken symlink.

So, I guess you have no choice than to break the atomicity, and do something like

ifnotos.path.exists(os.readlink(path)):
    print'path %s is a broken symlink' % path

Solution 2:

This is not atomic but it works.

os.path.islink(filename) and not os.path.exists(filename)

Indeed by RTFM (reading the fantastic manual) we see

os.path.exists(path)

Return True if path refers to an existing path. Returns False for broken symbolic links.

It also says:

On some platforms, this function may return False if permission is not granted to execute os.stat() on the requested file, even if the path physically exists.

So if you are worried about permissions, you should add other clauses.

Solution 3:

os.lstat() may be helpful. If lstat() succeeds and stat() fails, then it's probably a broken link.

Solution 4:

Can I mention testing for hardlinks without python? /bin/test has the FILE1 -ef FILE2 condition that is true when files share an inode.

Therefore, something like find . -type f -exec test \{} -ef /path/to/file \; -print works for hard link testing to a specific file.

Which brings me to reading man test and the mentions of -L and -h which both work on one file and return true if that file is a symbolic link, however that doesn't tell you if the target is missing.

I did find that head -0 FILE1 would return an exit code of 0 if the file can be opened and a 1 if it cannot, which in the case of a symbolic link to a regular file works as a test for whether it's target can be read.

Solution 5:

os.path

You may try using realpath() to get what the symlink points to, then trying to determine if it's a valid file using is file.

(I'm not able to try that out at the moment, so you'll have to play around with it and see what you get)

Post a Comment for "Find Broken Symlinks With Python"