Converting relative path to absolute path without symbolic link

88,308

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.

Share:
88,308
Benjamin
Author by

Benjamin

Updated on September 18, 2022

Comments

  • Benjamin
    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'
    Gilles 'SO- stop being evil' almost 12 years
    That'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
    iconoclast almost 11 years
    The -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
    Stéphane Chazelas about 9 years
    Note 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
    Stéphane Chazelas about 9 years
    Your 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
    Stéphane Chazelas about 9 years
    Your case check should be ..|../*) instead of ..*.
  • Stéphane Chazelas
    Stéphane Chazelas about 9 years
    There's one case of missing quotes in dirname $cwd
  • Sildoreth
    Sildoreth about 9 years
    Some systems come with neither readlink nor realpath – Solaris and HP-UX, in particular.
  • Anthon
    Anthon over 7 years
    You gu(r)ess wrong. E.g. if your path includes a space most of the above wont work.
  • dave_thompson_085
    dave_thompson_085 over 7 years
    or a glob char sometimes. And it doesn't resolve symlinks, as was requested.
  • vxtal
    vxtal over 7 years
    I've deleted my "comment" response regarding path names containing spaces and modified the "answer" part accordingly.
  • Mateusz Piotrowski
    Mateusz Piotrowski over 7 years
    Why 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'
    Gilles 'SO- stop being evil' over 7 years
    @MateuszPiotrowski Typo, I meant to write ||
  • Felipe Rodriguez
    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
    Adrian almost 5 years
    For 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 call greadlink.