Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Convert absolute paths to relative paths



It turned out I did care about minimizing the path, so here's what I
came up with:

# Print the a relative path from the second directory to the first,
# defaulting the second directory to $PWD if none is specified.
emulate -L zsh

[[ $1 != /* ]] && print $1 && return

local dir=${2:-$PWD}
[[ $1 == $dir ]] && print . && return

local -a cur abs
cur=(${(ps:/:)dir})	# Split 'current' directory into cur
abs=(${(ps:/:)1})	# Split target directory into abs

local min
((min = $#cur < $#abs ? $#cur : $#abs))
local i=1
while ((i <= $min)) && [[ $abs[1] == $cur[$i] ]]
do
  abs[1]=()	# Strip common prefix from target directory
  ((i=i+1))
done

# Figure out how many parents to get to common root
local relpath=
while ((i <= $#cur))
do
  relpath=../$relpath
  ((i=i+1))
done

relpath=$relpath${(j:/:)abs}
print ${relpath%/}


Bart Schaefer <schaefer@xxxxxxxxxxxxxxxx> writes:

> On Fri, 19 Apr 2002, Vin Shelton wrote:
>
>> Thanks, Bart!
>
> Christoph von Stuckrad pointed out privately that if you try to use this
> to get a relative path to a *file*, rather than to a directory, it will
> go into an infinite loop.
>
> Here's a fix for that:
>
> function relative {
>     emulate -L zsh
>     local up=.. down
>     [[ -d $1 ]] || 2=$1:t 1=$1:h
>     [[ -d $1 ]] || return 1
>     # ! -d $up/$down accounts for symlinks in $PWD
>     while [[ ${PWD#$1} == $PWD || ! -d $up/$down ]]
>     do
> 	up=../$up
> 	if [[ -n $1:t ]]
> 	then
> 	    down=$1:t${down:+/$down}
> 	    1=$1:h
> 	fi
>     done
>     print $up/$down${2:+/$2}
> }


  - vin



Messages sorted by: Reverse Date, Date, Thread, Author