http://www.perlmonks.org?node_id=32534

ddd has asked for the wisdom of the Perl Monks concerning the following question:

After a recent project that used File::Spec, File::Find, and others I'd like to add another section to tye's File::Spec review ('the good', 'the bad', and 'the ugly') ...

(Please forgive me for using unix paths in the following discussion)

The Unexpected

File::Spec->canonpath( $path ); does remove extra '/' and '/.' from paths, but it does not, however, fix paths like '/a/1/../2' into '/a/2'.

To do that I had to resort to regexps something like $path =~ s(\.\./)()g - which introduces platform-specific code and defeats the purpose of using File::Spec in the first place.

Q: What is the correct (x platform) method for removing 'dir/..' from paths?

A note on my ignorance: None of the systems that I use perl on (all 5.005_003 or older) have documentation (or code) for either abs2rel() or rel2abs() in File::Spec, or File::Spec::Unix. Are these new in 5.6? Perhaps theses functions are part of the answer to my question.

All the best,
DouglasDD

Replies are listed 'Best First'.
Re: Missing from File::Spec(?)
by tye (Sage) on Sep 14, 2000 at 23:21 UTC

    Actually, changing "/a1/a2/../a3" to "/a1/a3" can somethimes get you to a different directory. This is why File::Spec doesn't do that. This has to do with symbolic links and other not-strictly-tree-like possibilities in Unix-like file systems (automounted directories is another).

    For example, if "/a1/a2" is a symbolic link to "/b1/b2/b3" then "/a1/a2/../a3" should really become "/b1/b2/a3". And there is no "good" way to do that. One reasonable way is chdir("/a1/a2/../a3"); $path= getcwd(), but that doesn't always work either (though I'm getting old and tired and now usually feel that getcwd() not working is a good excuse for my script to not work as well).

            - tye (but my friends call me "Tye")
Re: Missing from File::Spec(?)
by merlyn (Sage) on Sep 14, 2000 at 23:19 UTC
    It doesn't do that because it (and you) cannot do that in general, because of symbolic links. If /a/b/c is a symbolic link to /d/e then /a/b/c/../f/g is /d/f/g not /a/b/f/g as your transformation would imply.

    I believe rel2abs does this correctly, but only on a live filesystem. You can't do this in a vacuum.

    -- Randal L. Schwartz, Perl hacker

Re: Missing from File::Spec(?)
by Fastolfe (Vicar) on Sep 14, 2000 at 23:13 UTC
    I believe the functions you note (specifically rel2abs()) will do this. They are in the man pages for File::Spec, but, like you, they don't exist in the modules installed on my system. They are either new with 5.6 or are just a new feature of File::Spec that I don't have.
    print rel2abs("../../../../../etc/./passwd"); # "/etc/passwd"