python readlink function

tl;dr

def readlinkf(_inpath):
   if os.path.islink(infile):
      return os.path.join(os.path.dirname(_inpath),os.readlink(_inpath))
   else:
      return _inpath

infile=readlinkf(infile)

Explanation

In GNU, there’s a fantastic utility named readlink. The main way I use it is to get the full and true path of a file or symlink.

For example:

$ ls foo .config/qux
.config/qux  foo
$ readlink -f foo
/home/bgstack15/.config/qux

In python, I wanted to achieve the same thing. it is possible with the os.path.islink and os.readlink functions. Here is my quick function for a readlink -f, since I didn’t find a specific implementation that outputs the full path.

Reference

Weblinks

  1. https://stackoverflow.com/questions/11068419/check-if-file-is-symlink-in-python

Online reference

  1. https://docs.python.org/3/library/os.path.html#os.path.islink
  2. https://docs.python.org/3.5/library/os.html#os.readlink

Search expressions

  1. python detect if file is symlink
  2. python readlink
Advertisements

Shell one-liners for manipulating symlinks

Showing symlink targets

I was trying to clean up a directory filled with files and symlinks. Many of the symlinks’ targets did not exist anymore (old package versions). I wrote a few one-liners to help me examine and clean up the directory.

Here’s the first one-liner.

find . -type l -print0 | sed -e 's/\.\///g;' | xargs -0 -n1 | while read line; do canon=$( readlink -f "${line}" 2>/dev/null ); test -e "${canon}" && echo "${line} is $( /bin/ls -d --color=always "${canon}" )" || echo "INVALID ${line}"; done

In expanded form:
find . -type l -print0 | \
sed -e 's/\.\///g;' | \
xargs -0 -n1 | \
while read line; do \
canon=$( readlink -f "${line}" 2>/dev/null );
test -e "${canon}" && echo "${line} is $( /bin/ls -d --color=always "${canon}" )" || echo "INVALID ${line}";
done

The find command lists symlinks in the current directory, with special null characters as the separators. This will allow correct operation with spaces in filenames. You don’t normally encounter this in GNU/Linux, but you never know!

The sed removes the dot slash ./ from the beginning of filenames. I just don’t like seeing that. If I had selected find * earlier, I wouldn’t need the sed command, but I would miss any files whose names begin with dot (e.g., .gitignore) and I would still find file . which I would have to exclude somehow anyway (well, not here because I’m searching for symlinks, but I personally never try to run find * no matter what).

xargs -0 -n1 now removes the null character separators, and feeds each individual entry one at a time to the next command.

While: So for each entry, read the symlink. If the target is a file, display it in whatever color ls would show it (without entering directories), because colors are pretty! Otherwise, print the line with “INVALID” in front of it.

Cleaning up the invalid symlinks

find . -type l -print0 | sed -e 's/\.\///g;' | xargs -0 -n1 | while read line; do canon=$( readlink -f "${line}" 2>/dev/null ); test -e "${canon}" && true || { echo /bin/rm "./${line}"; }; done
Replace the echo commands with true for the affirmative and the echo /bin/rm command.
To actually effect the change, remove the echo in front of /bin/rm.