Given an absolute or relative path (in a Unix-like system), I would like to determine the full path of the target after resolving any intermediate symlinks. Bonus points for also resolving ~username notation at the same time.
If the target is a directory, it might be possible to chdir() into the directory and then call getcwd(), but I really want to do this from a shell script rather than writing a C helper. Unfortunately, shells have a tendency to try to hide the existence of symlinks from the user (this is bash on OS X):
$ ls -ld foo bar drwxr-xr-x 2 greg greg 68 Aug 11 22:36 bar lrwxr-xr-x 1 greg greg 3 Aug 11 22:36 foo -> bar $ cd foo $ pwd /Users/greg/tmp/foo $
What I want is a function resolve() such that when executed from the tmp directory in the above example, resolve("foo") == "/Users/greg/tmp/bar".
According to the standards,
pwd -P should return the path with symlinks resolved.
char *getcwd(char *buf, size_t size) from
unistd.h should have the same behaviour.
readlink -f "$path"
Editor's note: The above works with GNU
readlink and FreeBSD/PC-BSD/OpenBSD
readlink, but not on OS X as of 10.11.
readlink offers additional, related options, such as
-m for resolving a symlink whether or not the ultimate target exists.
Note since GNU coreutils 8.15 (2012-01-06), there is a realpath program available that is less obtuse and more flexible than the above. It's also compatible with the FreeBSD util of the same name. It also includes functionality to generate a relative path between two files.
For Mac OS X (through at least 10.11.x), use
readlink without the
Editor's note: This will not resolve symlinks recursively and thus won't report the ultimate target; e.g., given symlink
a that points to
b, which in turn points to
c, this will only report
b (and won't ensure that it is output as an absolute path).
Use the following
perl command on OS X to fill the gap of the missing
readlink -f functionality:
perl -MCwd -le 'print Cwd::abs_path(shift)' "$path"