How to calculate a relative path from two absolute paths in Linux shell?

18

4

We have two paths. First one is directory, second either a directory or a file.

/a/b/c and /a/d/e.txt

Relative path from first path to second will be:

../../d/e.txt

How to calculate that in Linux terminal? For those who ask “What is usage case?” one could use this—for example—to create lots of relative symlinks.

Zebooka

Posted 2010-05-13T03:56:57.640

Reputation:

1This should not have been migrated. – None – 2010-05-13T04:52:49.807

1It should have been closed as a duplicate. – Paused until further notice. – 2010-05-13T10:19:56.150

Answers

10

Assuming GNU coreutils:

  • For symlinks, ln has recently learned the --relative option.

  • For everything else, realpath supports options --relative-to= and --relative-base=.

user1686

Posted 2010-05-13T03:56:57.640

Reputation: 283 655

1How do you do it with BusyBox? – DUzun – 2018-01-20T19:30:26.370

4

For me, this answer (which uses a python oneliner) works perfect.

$ python -c "import os.path; print os.path.relpath('/a/d/e.txt', '/a/b/c')"
../../d/e.txt

Tested successfully on linux (Kubuntu 14.04) an on Mac OSX, needs Python 2.6.

Joe

Posted 2010-05-13T03:56:57.640

Reputation: 381

2

To not depend on realpath that is not consistently available and minimize the dependencies, I came up with this (using a little help from this answer):

function relative_path_from_to() {
  # strip trailing slashes
  path1=${1%\/}
  path2=${2%\/}
  # common part of both paths
  common=$(printf '%s\x0%s' "${path1}" "${path2}" | sed 's/\(.*\).*\x0\1.*/\1/')
  # how many directories we have to go up to the common part
  up=$(grep -o "/" <<< ${path1#$common} | wc -l)
  # create a prefix in the form of ../../ ...
  prefix=""; for ((i=0; i<=$up; i++)); do prefix="$prefix../"; done
  # return prefix plus second path without common
  printf "$prefix${2#$common}"
}

Spawns a subshell for finding the common part of both pathes. Maybe you like it - works for me.

Pascal

Posted 2010-05-13T03:56:57.640

Reputation: 171