Convert absolute path into relative path given a current directory using Bash
Using realpath from GNU coreutils 8.23 is the simplest, I think:
$ realpath --relative-to="$file1" "$file2"
For example:
$ realpath --relative-to=/usr/bin/nmap /tmp/testing../../../tmp/testing
$ python -c "import os.path; print os.path.relpath('/foo/bar', '/foo/baz/foo')"
gives:
../../bar
This is a corrected, fully functional improvement of the currently best rated solution from @pini (which sadly handle only a few cases)
Reminder : '-z' test if the string is zero-length (=empty) and '-n' test if the string is not empty.
# both $1 and $2 are absolute paths beginning with /# returns relative path to $2/$target from $1/$sourcesource=$1target=$2common_part=$source # for nowresult="" # for nowwhile [[ "${target#$common_part}" == "${target}" ]]; do # no match, means that candidate common part is not correct # go up one level (reduce common part) common_part="$(dirname $common_part)" # and record that we went back, with correct / handling if [[ -z $result ]]; then result=".." else result="../$result" fidoneif [[ $common_part == "/" ]]; then # special case for root (no common path) result="$result/"fi# since we now have identified the common part,# compute the non-common partforward_part="${target#$common_part}"# and now stick all parts togetherif [[ -n $result ]] && [[ -n $forward_part ]]; then result="$result$forward_part"elif [[ -n $forward_part ]]; then # extra slash removal result="${forward_part:1}"fiecho $result
Test cases :
compute_relative.sh "/A/B/C" "/A" --> "../.."compute_relative.sh "/A/B/C" "/A/B" --> ".."compute_relative.sh "/A/B/C" "/A/B/C" --> ""compute_relative.sh "/A/B/C" "/A/B/C/D" --> "D"compute_relative.sh "/A/B/C" "/A/B/C/D/E" --> "D/E"compute_relative.sh "/A/B/C" "/A/B/D" --> "../D"compute_relative.sh "/A/B/C" "/A/B/D/E" --> "../D/E"compute_relative.sh "/A/B/C" "/A/D" --> "../../D"compute_relative.sh "/A/B/C" "/A/D/E" --> "../../D/E"compute_relative.sh "/A/B/C" "/D/E/F" --> "../../../D/E/F"