How to calculate a relative path from two absolute paths in Linux shell?
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.
Related videos on Youtube
techraf
This user really prefers to keep an air of mystery about them.
Updated on September 17, 2022Comments
-
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 almost 14 yearsThis should not have been migrated.
-
Admin almost 14 yearsIt should have been closed as a duplicate.
-
-
DUzun over 6 yearsHow do you do it with BusyBox?
-
mems about 4 yearsBe 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 tos/\(.*\/\).*\x0\1.*/\1/
(force end with a slash) -
Pascal almost 4 yearsHi @mems - you are totally right. Thank you for the fix. This is what you get if you don't write test cases...