Converting relative path to absolute path without symbolic link
Solution 1
You can use the readlink
utility, with the -f
option:
-f, --canonicalize
canonicalize by following every symlink in every component of the given name recursively; all but the last component must exist
Some distributions, for example those that use GNU coreutils and FreeBSD, also come with a realpath(1)
utility that basically just calls realpath(3)
and does pretty much the same thing.
Solution 2
Portably, the PWD
variable is set by the shell to one absolute location of the current directory. Any component of that path may be a symbolic link.
case $f in
/*) absolute=$f;;
*) absolute=$PWD/$f;;
esac
If you want to eliminate .
and ..
as well, change to the directory containing the file and obtain $PWD
there:
if [ -d "$f" ]; then f=$f/.; fi
absolute=$(cd "$(dirname -- "$f")"; printf %s. "$PWD")
absolute=${absolute%?}
absolute=$absolute/${f##*/}
There's no portable way to follow symbolic links. If you have a path to a directory, then on most unices $(cd -- "$dir" && pwd -P 2>/dev/null || pwd)
provides a path that doesn't use symbolic links, because shells that track symbolic links tend to implement pwd -P
(“P” for “physical”).
Some unices provide a utility to print the “physical” path to a file.
- Reasonably recent Linux systems (with GNU coreutils or BusyBox) have
readlink -f
, as do FreeBSD ≥8.3, NetBSD ≥4.0, and OpenBSD as far back as 2.2. - FreeBSD ≥4.3 has
realpath
(it's also present on some Linux systems, and it's in BusyBox). -
If Perl is available, you can use the
Cwd
module.perl -MCwd -e 'print Cwd::realpath($ARGV[0])' path/to/file
Solution 3
Is pwd
fit for your needs? It gives the absolute path of current directory. Or maybe what you want is realpath().
Solution 4
alister
and rss67
in this article introduce most stable, compatible and easiest way. I never seen better way than this before.
RELPATH=./../
cd $RELPATH
ABSPATH=`pwd`
If you want to go back to the original location,
ORGPATH=`pwd`
RELPATH=./../
cd $RELPATH
ABSPATH=`pwd`
cd $ORGPATH
or
RELPATH=./../
cd $RELPATH
ABSPATH=`pwd`
cd -
I wish this helps. This was greatest solution for me.
Benjamin
Updated on September 18, 2022Comments
-
Benjamin almost 2 years
Is there a Unix command to get the absolute (and canonicalized) path from a relative path which may contain symbolic links?
-
Gilles 'SO- stop being evil' almost 12 yearsThat's actually not such a good way. Changing out of a directory and back in is not reliable: you might not have the permission to come back, or the directory might have been renamed in the meantime. Instead, change directories in a subshell:
ABSPATH=$(cd -- "$RELPATH" && pwd)
. Note the double quotes around substitution (so as not to break if the path contains whitespace and globbing characters) and the--
(in case the path begins with-
). Also this only works for directories, and doesn't canonicalize symbolic links as requested. See my answer for more details. -
iconoclast almost 11 yearsThe
-f
switch does not exist on Mac OS X (at least as of 10.8.5). Without the-f
switch it just returns an error code. -
Stéphane Chazelas about 9 yearsNote that you'll probably only find a Bourne shell on Solaris 10 and earlier nowadays. That Bourne shell like most Bourne shell implementations since SVR2 (1984) has
pwd
builtin and doesn't support-P
(the Bourne shell did not implement that logical $PWD handling like POSIX shells do). -
Stéphane Chazelas about 9 yearsYour forget to check the exit status of cd (and pwd). You should probably use
cd -P --
as well in case the 1st argument contains some .. -
Stéphane Chazelas about 9 yearsYour
case
check should be..|../*)
instead of..*
. -
Stéphane Chazelas about 9 yearsThere's one case of missing quotes in
dirname $cwd
-
Sildoreth about 9 yearsSome systems come with neither
readlink
norrealpath
– Solaris and HP-UX, in particular. -
Anthon over 7 yearsYou gu(r)ess wrong. E.g. if your path includes a space most of the above wont work.
-
dave_thompson_085 over 7 yearsor a glob char sometimes. And it doesn't resolve symlinks, as was requested.
-
vxtal over 7 yearsI've deleted my "comment" response regarding path names containing spaces and modified the "answer" part accordingly.
-
Mateusz Piotrowski over 7 yearsWhy do you pipe something into
pwd
($(cd -- "$dir" && pwd -P 2>/dev/null | pwd)
)? It doesn't seem to care about stdin. -
Gilles 'SO- stop being evil' over 7 years@MateuszPiotrowski Typo, I meant to write
||
-
Felipe Rodriguez about 5 years"> you might not have the permission to come back" You mean cd to a dir but cannot cd back ? Could you please provide some example scenarios.
-
Adrian almost 5 yearsFor the Mac issue:
brew install coreutils
apple.stackexchange.com/a/69332/23040, and if you don't want to do the step that redirects all standard Mac CLI tools to the newly-installed GNU equivalents, just callgreadlink
.