What's the difference between "realpath" and "readlink -f"

There are several realpath commands around.

The realpath utility is a wrapper around the realpath library functions and has been reinvented many times.

Debian used to maintain a realpath package (separated from dwww since woody) which hasn't changed except regarding packaging and documentation since 2001, but has now been phased out. This utility was deprecated because there are now more standard alternatives (GNU readlink and soon GNU realpath), but at the time, GNU utilities didn't even have readlink at all. This implementation of realpath supports a few options to prevent symbolic link resolution or produce null-terminated output. BusyBox also includes its own realpath command (which takes no option).

GNU coreutils introduced a realpath command in version 8.15 in January 2012. This is a compatible replacement for BusyBox's and Debian's realpath, and also has many options in common with GNU readlink.

realpath has the same effect as readlink -f with GNU readlink. What distinguishes the two commands (or rather the various realpath commands from readlink -f) is the extra options that they support.

GNU realpath is not deprecated; it has the opposite problem: it's too new to be available everywhere. Debian used to omit GNU realpath from its coreutils package and stick with its own realpath. I don't know why, since GNU realpath should be a drop-in replacement. As of Debian jessie and Ubuntu 16.04, however, GNU realpath is used.

On Linux systems, at the moment, your best bet to canonicalize a path that may contain symbolic links is readlink -f.

BSD systems have a readlink command, with different capabilities from GNU readlink. In particular, BSD readlink does not have an option to canonicalize paths, it only traverses the symlink passed to it.

readlink, incidentally, had the same problem — it was also invented many times (not adding this utility when symbolic links were added to Unix was a regrettable omission). It has now stabilized in several implementations with many incompatible flags (in particular BSD vs. GNU).


tl;dr readlink -f will return 0 for a non-existent file in an existing directory whereas realpath returns 1. However, readlink -e will behave like realpath and return 1 for a non-existent file (see Editors note at end).

readlink -f

$ readlink -f non-existent-file
/home/user/non-existent-file
$ echo $?
0

readlink -e

$ readlink -e non-existent-file
$ echo $?
1

realpath

$ realpath non-existent-file
non-existent-file: No such file or directory
$ echo $?
1

readlink -f with non-existent directory

readlink -f behavior varies depending upon which part of the path does not exist.

$ readlink -f /tmp/non-existent-dir/foo
$ echo $?
1

realpath with non-existent directory

$ realpath /tmp/non-existent-dir/foo
$ echo $?
1

Availablity

readlink is installed within most Linux distributions. Whereas, realpath must often be explicitly installed.

In summary

If you want to replace calls to realpath ... then use readlink -e ....

MMV readlink implementations vary widely.


Tested with readlink (GNU coreutils) 8.21 and realpath version 1.19 on Ubuntu 16.

(Ed.: @AnthonyGeoghegan wrote "this refers to the Debian version of realpath. The GNU version of realpath behaves the same as readlink -f")
(Ed.: @FilBot3 wrote "this doesn't work on MacOS High Sierra")

Tags:

Shell

Command