Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find relative path given two absolute paths?

Given two absolute paths, e.g.

  • /a/path/to/a
  • /a/path/to/somewhere/else

How can I get a relative path from one to the other, ../a?

In a sense, the opposite of what realpath does.

like image 826
congusbongus Avatar asked Mar 14 '15 23:03

congusbongus


4 Answers

I answered a similar question here: Resolving a relative path without referencing the current directory on Windows.

There is no standard function for this. There is a function in vi-like-emacs for this purpose. A quick check of apropos relative shows me few other programs which likely implement this: revpath for example).

It could be done as a string-manipulation (no need to compute working directories):

  • start by finding the longest common prefix which ends with a path-separator.
  • if there is no common prefix, you are done
  • strip the common prefix from (a copy of...) the current and target strings
  • replace each directory-name in the current string with ".."
  • add that (with a path-separator) in front of the target string
  • return that combined string

The "done" in the second step presumes that you want to use a relative path to shorten the result. On the other hand, you might want to use a relative pathname regardless of the length. In that case, just skip the step (the result will be longer, but relative).

like image 168
Thomas Dickey Avatar answered Sep 19 '22 04:09

Thomas Dickey


Find the longest common path (in this case, /a/path/to) and delete it from both absolute paths. That would give:

  • /a
  • /somewhere/else

Now, replace each path component in the starting path with ../ and prepend the result to the destination path. If you want to go from directory else to directory a, that would give you:

../../a

If you want to go the other way, you'd instead have:

../somewhere/else
like image 45
Caleb Avatar answered Sep 22 '22 04:09

Caleb


Build a tree with the first absolute path, then add the second path to that tree, and then walk from one leaf to the other: a step from one node to its parent is translated to a "../" sequence, and a step from a node to one of its children is translated to the name of that children. Notice that there might be more than one solution. For example:

1) /a/path/to/a

And

2) /a/path/to/a/new/one

The obvious path from (1) to (2) is new/one but ../../../a/path/to/a/new/one is also valid. When you write the algorithm to do the walking in your tree you have to be aware of this

like image 36
mcleod_ideafix Avatar answered Sep 22 '22 04:09

mcleod_ideafix


Using cwalk you can use cwk_path_get_relative, which even works cross-platform:

#include <cwalk.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
  char buffer[FILENAME_MAX];

  cwk_path_get_relative("/hello/there/", "/hello/world", buffer, sizeof(buffer));
  printf("The relative path is: %s", buffer);

  return EXIT_SUCCESS;
}

Output:

The relative path is: ../world
like image 28
Julius Avatar answered Sep 23 '22 04:09

Julius