Re: How to get a true canonical path
by eserte (Deacon) on Jun 09, 2004 at 14:32 UTC
|
| [reply] [Watch: Dir/Any] |
|
Yeh - that figures out links pretty well..
use strict;
use Cwd 'abs_path';
my $fileinquestion = "/var/mail/";
my $realpathfor = abs_path($fileinquestion);
print "$realpathfor\n";
If you have to be out inside a system operation, the value of
pwd -P
is pretty real
Out of curiosity I tried a .. operation under win2k with AS.. it seems to work..
#!perl
use strict;
use Cwd;
use Cwd 'abs_path';
my $q = 'C:\\TEMP\\';
chdir $q;
my $dirnow = getcwd();
print "Changed dir to C:\\TEMP\n";
print "Cwd thinks I am in $dirnow\n";
chdir "..\\";
print "Changed dir up one level ..\n";
my $newdirnow = getcwd();
print "Cwd now thinks I am in $newdirnow\n";
so that might do the right thing if a user provides input including \path\..\another\path, so long as backslashes get treated correctly
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
| [reply] [Watch: Dir/Any] |
|
Not on my system (perl5.8.0):
$ perl -MCwd=abs_path -e 'warn abs_path("$ENV{HOME}/../slavenr/.cshrc"
+)'
/home/slavenr/.cshrc at -e line 1.
| [reply] [Watch: Dir/Any] [d/l] |
Re: How to get a true canonical path
by valdez (Monsignor) on Jun 09, 2004 at 16:01 UTC
|
#!/usr/bin/perl
use strict;
use warnings;
use URI;
my $base_uri = URI->new( '/home/httpd/project/' );
while (my $path = <DATA>) {
chomp($path);
my $absolute = URI->new_abs( $path, $base_uri );
printf "%s + %s: %s\n", $base_uri->canonical, $path, $absolute->cano
+nical;
}
__DATA__
../another/
subdir/
../../../etc/very/dangerous
../project/
update: it seems that I didn't understand the question, sorry.
update2: However, it seems that URI::file does understand OS differences and does what you want:
use URI::file;
my $base_uri = URI::file->new( URI::file->cwd );
while (my $path = <DATA>) {
chomp($path);
my $absolute = URI::file->new_abs( $path, $base_uri );
printf "%s + %s: %s\n", $base_uri->canonical, $path, $absolute->file
+;
}
__DATA__
../another/
subdir/
../../../some/other/place
../project/
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: How to get a true canonical path
by mojotoad (Monsignor) on Jun 09, 2004 at 16:38 UTC
|
Why not just leave the '..' portions in the path? Though the result, after having removed them, might be more aesthetically pleasing, it's really up to the OS how to interpret the updir. To "do the right thing" you probably will end up needing to chdir followed by a cwd.
For a more thorough discussion of what you're up against, check out some of my comments in Absolute pathnames from relative?.
Matt
| [reply] [Watch: Dir/Any] |
Re: How to get a true canonical path
by jepri (Parson) on Jun 09, 2004 at 14:28 UTC
|
This is easy to do if you just want to handle ".." in paths. Not too much code is needed - usually just let the shell resolve the path. But if you want to handle symlinks in Unix, then you are in a world of confusion.
If you want to demand a GNU environment, there is a GLIBC function called something like "cannonical_path" which will do all the work for you. Otherwise... ouch.
| [reply] [Watch: Dir/Any] |
Re: How to get a true canonical path
by pelagic (Priest) on Jun 09, 2004 at 21:14 UTC
|
$abs_file = File::Spec->rel2abs( $_, $directory );
$canon_file = elimupdir( $abs_file );
sub elimupdir {
my $foo = shift;
my( $volume, $directories, $file ) = File::Spec->splitpath(File::S
+pec->canonpath( $foo ));
my( @dur ) = File::Spec->splitdir( $directories );
my @dar;
foreach(@dur){
if( $_ eq $updir ){
pop @dar;
} else {
push @dar, $_;
}
}
return File::Spec->catpath(
$volume,
File::Spec->catdir( @dar ),
$file
);
}
| [reply] [Watch: Dir/Any] [d/l] |
|
Sub is nice, here is returns relative path to current directory:
# sub file_normalize: based on https://www.perlmonks.org/?node_id=3628
+93
sub file_normalize {
use File::Spec::Functions;
my $dir_ref = ".";
my $file = shift;
$file = File::Spec->rel2abs($file);
my( $volume, $directories, $basename ) = File::Spec->splitpath(File::
+Spec->canonpath($file));
my @dirs_in = File::Spec->splitdir( $directories );
my @dirs_out;
for my $dir (@dirs_in) {
if ($dir eq "..") {
pop @dirs_out;
} else {
push(@dirs_out, $dir);
}
}
return File::Spec->abs2rel(File::Spec->catpath($volume, File::Spec->c
+atdir(@dirs_out), $basename), $dir_ref);
}
| [reply] [Watch: Dir/Any] [d/l] |
|
Nitpicks: File::Spec::Functions doesn't need to be loaded since it isn't being used, and since File::Spec is already being used, I'd recommend File::Spec->curdir and File::Spec->updir instead of "." and "..".
But as was already mentioned in this thread, such logical cleanups have potentially major caveats. Going out to the filesystem with Cwd's abs_path and related is generally better.
| [reply] [Watch: Dir/Any] [d/l] [select] |