in reply to How to get the unique canonical path of a given path?
With you code safe-guarded against the above remarks, here is a compare of the methods mentioned in this thread plus the one I would use: Cwd::abs_path. Note that abs_path returns undef for non-existing path.
#!/usr/bin/perl use 5.018003; use warnings; use Cwd qw( abs_path ); use Path::Tiny; use File::Spec; my @pth = qw( /a/b/c/d/../../../e /a/../b/./c//d ../scripting ./tmp /tmp/../../../tmp ); sub resolves { my ($p, $r) = @_; printf "%-20s -> %s\n", $p, $r // "$p does not resolve"; } # resolves say "OP"; foreach my $pth (@pth) { my @c = reverse split m{/+}, $pth; # /+ removes empty elements my @c_new; while (@c) { my $component = shift @c; next unless length ($component); $component eq "." and @c and next; if ($component eq ".." and @c) { my $i = 0; while ($i <= $#c && $c[$i] =~ m/^\.{0,2}$/) { $i++; } splice @c, $i, 1; next; } push @c_new => $component; } @c = reverse @c_new; $c[0] =~ m/^\.\.?$/ or unshift @c => ""; resolves $pth, join "/" => @c; } say "Cwd::abs_path"; foreach my $pth (@pth) { resolves $pth, abs_path ($pth); + } say "Path::Tiny::path"; foreach my $pth (@pth) { resolves $pth, Path::Tiny::path ($pth); + } say "File::Spec::canonpath"; foreach my $pth (@pth) { resolves $pth, File::Spec->canonpath ($pth); + }
which produces
OP /a/b/c/d/../../../e -> /a/e /a/../b/./c//d -> /b/c/d ../scripting -> ../scripting ./tmp -> ./tmp /tmp/../../../tmp -> /tmp Cwd::abs_path /a/b/c/d/../../../e -> /a/b/c/d/../../../e does not resolve /a/../b/./c//d -> /a/../b/./c//d does not resolve ../scripting -> /home/scripting ./tmp -> /home/merijn/tmp /tmp/../../../tmp -> /tmp Path::Tiny::path /a/b/c/d/../../../e -> /a/b/c/d/../../../e /a/../b/./c//d -> /a/../b/c/d ../scripting -> ../scripting ./tmp -> tmp /tmp/../../../tmp -> /tmp/../../../tmp File::Spec::canonpath /a/b/c/d/../../../e -> /a/b/c/d/../../../e /a/../b/./c//d -> /a/../b/c/d ../scripting -> ../scripting ./tmp -> tmp /tmp/../../../tmp -> /tmp/../../../tmp
|
|---|