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

23,431

Solution 1

Assuming GNU coreutils:

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

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

Solution 2

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.

Solution 3

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. I hope you like it - works for me.

Share:
23,431

Related videos on Youtube

techraf
Author by

techraf

This user really prefers to keep an air of mystery about them.

Updated on September 17, 2022

Comments

  • techraf
    techraf over 1 year

    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.

    • Admin
      Admin almost 14 years
      This should not have been migrated.
    • Admin
      Admin almost 14 years
      It should have been closed as a duplicate.
  • DUzun
    DUzun over 6 years
    How do you do it with BusyBox?
  • mems
    mems about 4 years
    Be careful common this doesn't work for relative_path_from_to /path/test1/file /path/test2/file gives ../../2/file instead of ../../test2/file. To fix that the sed part must be updated to s/\(.*\/\).*\x0\1.*/\1/ (force end with a slash)
  • Pascal
    Pascal almost 4 years
    Hi @mems - you are totally right. Thank you for the fix. This is what you get if you don't write test cases...