* 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).