zsh-users
 help / color / mirror / code / Atom feed
* Convert absolute paths to relative paths
@ 2002-04-19 11:49 Vin Shelton
  2002-04-19 17:51 ` Bart Schaefer
  0 siblings, 1 reply; 7+ messages in thread
From: Vin Shelton @ 2002-04-19 11:49 UTC (permalink / raw)
  To: zsh-users

Greetings -

Can anyone show me some nifty zsh hackery to convert a string
representing an absolute path into a relative path?  For example, if
my current $PWD is "/opt/build" and the path I want to convert is
"/opt/src/perl-5.6.1", I would like the result to be
"../src/perl-5.6.1".

Thanks in advance,
  Vin Shelton 


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Convert absolute paths to relative paths
  2002-04-19 11:49 Convert absolute paths to relative paths Vin Shelton
@ 2002-04-19 17:51 ` Bart Schaefer
  2002-04-19 19:00   ` Bart Schaefer
  2002-04-20  0:47   ` Vin Shelton
  0 siblings, 2 replies; 7+ messages in thread
From: Bart Schaefer @ 2002-04-19 17:51 UTC (permalink / raw)
  To: Vin Shelton, zsh-users

On Apr 19,  7:49am, Vin Shelton wrote:
}
} Can anyone show me some nifty zsh hackery to convert a string
} representing an absolute path into a relative path?  For example, if
} my current $PWD is "/opt/build" and the path I want to convert is
} "/opt/src/perl-5.6.1", I would like the result to be
} "../src/perl-5.6.1".

function relative {
    emulate -L zsh
    local up=.. down
    # ! -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
}

-- 
Bart Schaefer                                 Brass Lantern Enterprises
http://www.well.com/user/barts              http://www.brasslantern.com

Zsh: http://www.zsh.org | PHPerl Project: http://phperl.sourceforge.net   


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Convert absolute paths to relative paths
  2002-04-19 17:51 ` Bart Schaefer
@ 2002-04-19 19:00   ` Bart Schaefer
  2002-04-20  0:47   ` Vin Shelton
  1 sibling, 0 replies; 7+ messages in thread
From: Bart Schaefer @ 2002-04-19 19:00 UTC (permalink / raw)
  To: zsh-users

On Apr 19,  5:51pm, Bart Schaefer wrote:
}
} function relative {

By the way, that function always computes a correct path, but it may be
a "sub-optimal" one (too many ..).  Short-circuiting it at the minimal
number of .. is left as an exercise.

-- 
Bart Schaefer                                 Brass Lantern Enterprises
http://www.well.com/user/barts              http://www.brasslantern.com

Zsh: http://www.zsh.org | PHPerl Project: http://phperl.sourceforge.net   


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Convert absolute paths to relative paths
  2002-04-19 17:51 ` Bart Schaefer
  2002-04-19 19:00   ` Bart Schaefer
@ 2002-04-20  0:47   ` Vin Shelton
  2002-04-20  0:59     ` Bart Schaefer
  1 sibling, 1 reply; 7+ messages in thread
From: Vin Shelton @ 2002-04-20  0:47 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: zsh-users

Thanks, Bart!

  - vin

"Bart Schaefer" <schaefer@brasslantern.com> writes:

> On Apr 19,  7:49am, Vin Shelton wrote:
> }
> } Can anyone show me some nifty zsh hackery to convert a string
> } representing an absolute path into a relative path?  For example, if
> } my current $PWD is "/opt/build" and the path I want to convert is
> } "/opt/src/perl-5.6.1", I would like the result to be
> } "../src/perl-5.6.1".
>
> function relative {
>     emulate -L zsh
>     local up=.. down
>     # ! -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
> }
>
> -- 
> Bart Schaefer                                 Brass Lantern Enterprises
> http://www.well.com/user/barts              http://www.brasslantern.com
>
> Zsh: http://www.zsh.org | PHPerl Project: http://phperl.sourceforge.net   


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Convert absolute paths to relative paths
  2002-04-20  0:47   ` Vin Shelton
@ 2002-04-20  0:59     ` Bart Schaefer
  2002-04-20  4:48       ` Vin Shelton
  0 siblings, 1 reply; 7+ messages in thread
From: Bart Schaefer @ 2002-04-20  0:59 UTC (permalink / raw)
  To: Vin Shelton; +Cc: zsh-users

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}
}


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Convert absolute paths to relative paths
  2002-04-20  0:59     ` Bart Schaefer
@ 2002-04-20  4:48       ` Vin Shelton
  2002-04-21 18:32         ` Bart Schaefer
  0 siblings, 1 reply; 7+ messages in thread
From: Vin Shelton @ 2002-04-20  4:48 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: zsh-users

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@brasslantern.com> 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


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Convert absolute paths to relative paths
  2002-04-20  4:48       ` Vin Shelton
@ 2002-04-21 18:32         ` Bart Schaefer
  0 siblings, 0 replies; 7+ messages in thread
From: Bart Schaefer @ 2002-04-21 18:32 UTC (permalink / raw)
  To: Vin Shelton; +Cc: zsh-users

On Apr 20, 12:48am, Vin Shelton wrote:
} Subject: 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:

That's a more interesting algorithm than mine.  Assorted suggestions ...

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

Add something like:

[[ -f $1 ]] && 1=$1:h
[[ -d $1 ]] || return 1

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

Replace with:

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

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

You don't need the (p) flag there, you aren't using any prompt escapes.
To be really thorough, you should also eliminate any uses of ./ or ../
in either path.

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

Replace with:

local relpath=${(j:/:)cur/*/..}

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

In case of symlinks, you should test that the resulting $relpath actually
exists.

So the whole thing becomes:

---- 8< ----
# 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 || return 1

[[ $1 != /* ]] && print $1 && return
[[ -f $1 ]] && 3=$1:t 1=$1:h
[[ -d $1 && -d ${2:=$PWD} ]] || return 1
[[ $1 -ef $2 ]] && print ${3:-.} && return

# The simplest way to eliminate symlinks and ./ and ../ in the paths:
1=$(cd $1; pwd -r)
2=$(cd $2; pwd -r)

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

# Compute the length of the common prefix, or discover a subdiretory:
integer i=1
while [[ i -le $#abs && $abs[i] == $cur[i] ]]
do
    ((++i > $#cur)) && print ${(j:/:)abs[i,-1]} && return
done

2=${(j:/:)cur[i,-1]/*/..}	# Up to the common prefix directory and
1=${(j:/:)abs[i,-1]}		# down to the target directory or file

print $2${1:+/$1}

-- 
Bart Schaefer                                 Brass Lantern Enterprises
http://www.well.com/user/barts              http://www.brasslantern.com

Zsh: http://www.zsh.org | PHPerl Project: http://phperl.sourceforge.net   


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2002-04-21 18:32 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-04-19 11:49 Convert absolute paths to relative paths Vin Shelton
2002-04-19 17:51 ` Bart Schaefer
2002-04-19 19:00   ` Bart Schaefer
2002-04-20  0:47   ` Vin Shelton
2002-04-20  0:59     ` Bart Schaefer
2002-04-20  4:48       ` Vin Shelton
2002-04-21 18:32         ` Bart Schaefer

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).