How to resolve symbolic links in a shell script
One of my favorites is realpath foo
realpath - return the canonicalized absolute pathname realpath expands all symbolic links and resolves references to '/./', '/../' and extra '/' characters in the null terminated string named by path and stores the canonicalized absolute pathname in the buffer of size PATH_MAX named by resolved_path. The resulting path will have no symbolic link, '/./' or '/../' components.
According to the standards, pwd -P
should return the path with symlinks resolved.
C function char *getcwd(char *buf, size_t size)
from unistd.h
should have the same behaviour.
getcwd pwd
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.
GNU 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.
realpath $path
[Admin addition below from comment by halloleo —danorton]
For Mac OS X (through at least 10.11.x), use readlink
without the -f
option:
readlink $path
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"
"pwd -P" seems to work if you just want the directory, but if for some reason you want the name of the actual executable I don't think that helps. Here's my solution:
#!/bin/bash
# get the absolute path of the executable
SELF_PATH=$(cd -P -- "$(dirname -- "$0")" && pwd -P) && SELF_PATH=$SELF_PATH/$(basename -- "$0")
# resolve symlinks
while [[ -h $SELF_PATH ]]; do
# 1) cd to directory of the symlink
# 2) cd to the directory of where the symlink points
# 3) get the pwd
# 4) append the basename
DIR=$(dirname -- "$SELF_PATH")
SYM=$(readlink "$SELF_PATH")
SELF_PATH=$(cd "$DIR" && cd "$(dirname -- "$SYM")" && pwd)/$(basename -- "$SYM")
done