Re: Collapsing paths
by tirwhan (Abbot) on Dec 05, 2007 at 12:45 UTC
|
As also pointed out in File::Specs documentation, you can use the "realpath" function from Cwd for this. This will however return an absolute path and only resolve paths which actually exist in your filesystem (this is a feature, not a bug, because it's the only way to correctly handle symlinks).
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
| [reply] [Watch: Dir/Any] |
Re: Collapsing paths
by merlyn (Sage) on Dec 05, 2007 at 17:02 UTC
|
Just to be very specific, since the other answers in this thread only skirt around the issue (and some ignore it entirely and therefore do the wrong thing)...
You do realize that "foo/../bar/bletch" cannot be reduced unless you're absolutely sure that "foo" is not a symlink, correct? Because if it is a symlink, then the ".." is relative to where "foo" points, not to where "foo" itself is located.
| [reply] [Watch: Dir/Any] |
|
Great point, thanks. There are no symlinks in the structure I'm moving around so it's not an issue in this case, though.
| [reply] [Watch: Dir/Any] |
Re: Collapsing paths
by shmem (Chancellor) on Dec 05, 2007 at 14:44 UTC
|
qwurx [shmem] ~ > perl -MCwd=abs_path -le 'print abs_path("/usr/lib/pe
+rl5/../../lib/perl5")'
/usr/lib/perl5
--shmem
_($_=" "x(1<<5)."?\n".q·/)Oo. G°\ /
/\_¯/(q /
---------------------------- \__(m.====·.(_("always off the crowd"))."·
");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
| [reply] [Watch: Dir/Any] [d/l] |
Re: Collapsing paths
by oha (Friar) on Dec 05, 2007 at 12:52 UTC
|
if you are interested in doing it with regexp:
{ $path =~ s{(^|/)(\w+/\.\./|\./)}{$1} and redo }
which collapses ./ and <dir>/../
Oha | [reply] [Watch: Dir/Any] [d/l] |
|
1 while $path =~ s{(^|/)(\w+/\.\./|\./)}{$1};
It's even shorter.
| [reply] [Watch: Dir/Any] [d/l] |
Re: Collapsing paths
by johngg (Canon) on Dec 05, 2007 at 14:34 UTC
|
I have a module that includes this code ref. that you should be able to adapt to do what you want.
# ----------
my $_cleanPath = sub
# ----------
{
my $absPath = shift;
return $absPath if $absPath =~ m{^/$};
my @elems = split m{/}, $absPath;
my $ptr = 1;
while( $ptr <= $#elems )
{
if( $elems[ $ptr ] eq q{} )
{
splice @elems, $ptr, 1;
}
elsif( $elems[ $ptr ] eq q{.} )
{
splice @elems, $ptr, 1;
}
elsif( $elems[ $ptr ] eq q{..} )
{
if( $ptr < 2 )
{
splice @elems, $ptr, 1;
}
else
{
$ptr --;
splice @elems, $ptr, 2;
}
}
else
{
$ptr ++;
}
}
return $#elems ? join q{/}, @elems : q{/};
};
I hope this is of use. Cheers, JohnGG | [reply] [Watch: Dir/Any] [d/l] |
Re: Collapsing paths
by lodin (Hermit) on Dec 05, 2007 at 12:45 UTC
|
use File::Spec::Functions 'canonpath';
print canonpath('foo/../bar/../baz/');
__END__
baz
lodin
Update: added examplifying code, but see ikegami's reply below. | [reply] [Watch: Dir/Any] [d/l] [select] |
|
canonpath in File::Spec seems to do the trick.
Did you try it out?
#!/usr/bin/perl
use File::Spec;
print File::Spec->canonpath("foo/../bar/../baz/")."\n";
Output:
foo/../bar/../baz
I guess not. Did you read the docs? Quote:
Note that this does *not* collapse x/../y sections into y. This is by design.
I guess not.
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
use File::Spec;
print File::Spec->canonpath("foo/../bar/../baz/")."\n";
\baz
On system without symlinks, canonpath collapses x/../y (although not always correctly, as shown above).
Update: Technically, NTFS does have symlinks, but most software act as if they don't exist, including File::Spec.
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
| [reply] [Watch: Dir/Any] |
|
I don't think it does, it looks like it removes extraneous slashes, but doesn't collapse ../../ path fragments.
| [reply] [Watch: Dir/Any] [d/l] |