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

Please forgive me if this is something everyone else knows! I have searched for 'directory separator' with no results here on Perl Monks.

I want to get the current OS directory separator into a var so that I can use it in string substitution.

Help! & thanks in advance

Jeff

  • Comment on Platform independant directory separator

Replies are listed 'Best First'.
Re: Platform independant directory separator
by rinceWind (Monsignor) on Mar 01, 2004 at 14:08 UTC
    I want to get the current OS directory separator into a var so that I can use it in string substitution.
    On some platforms, there is not a single separator. VMS for example has the syntax
    DEVICE:[DIR.PATH]FILENAME.EXT;VER
    Although '.' is the separator between components of the path, the whole directory is encased in brackets.

    I advise going with what others suggest, with File::Spec and File::Spec::Functions. Note that the functions splitpath and splitdir do what you are looking for, returning a list of path elements (list context). You can work on the list of strings and join them back together again with catpath or catdir.

    Note that all O/S that run Perl support POSIX filenames, which means that you can use forward slash as a directory separator. This is how the standard module installs work, supplying filespecs such as t/mytest.t and -Iblib/lib.

    Also note that usually you cannot mix native and POSIX directory separators (Windows lets you get away with it sometimes). So to write portable code that works with native filespecs, I recommend sticking to File::Spec.

    See also the slides for a talk I gave recently on portability.

    --
    I'm Not Just Another Perl Hacker

Re: Platform independant directory separator
by Roger (Parson) on Mar 01, 2004 at 12:36 UTC
    Use the canonpath function in the File::Spec::Functions module. It's part of the Perl's core distribution.

    use File::Spec::Functions qw/ canonpath /; # it's a good idea to use relative path for portability my $platform_independent_path = canonpath "../data/somepath/somedata.txt"; my $directory_separator = canonpath "/";

      my $platform_independent_path =       canonpath "../data/somepath/somedata.txt"; my $directory_separator =       canonpath "/";

      Erm. No.

      All canonpath does is clear up a directory in to a canonical for for a specific platform - it's not platform independent in any way.

      For example running your code on a Mac OS 9 box would set $directory_separator to "/" when it would more accurately be ":".

      As rinceWind points out the idea of a single separator isn't valid on some platforms in any case.

Re: Platform independant directory separator
by tinita (Parson) on Mar 01, 2004 at 12:28 UTC
    uhm, you could use File::Spec::catfile, like
    my $sep = File::Spec->catfile('', '');
    i actually wonder why File::Spec doesn't provide a variable for this...

    Update: ok, after reading rinceWind's answer I can see why.

Re: Platform independant directory separator
by Hena (Friar) on Mar 01, 2004 at 12:29 UTC
    Try module File::Spec (perldoc File::Spec). It provides a set of functions to handle paths.
Re: Platform independant directory separator
by Grygonos (Chaplain) on Mar 01, 2004 at 12:27 UTC

    $^O tells you what OS is running. You can use / or \\ accordingly then. In most cases, the / version works for both OS's. However in certain modules like Win32::OLE the Windows style \\ must be used.

    Checking $^O is always safe though.

    Grygonos
      > You can use / or \\ accordingly then.
      but there are more than two operating systems...
        Yes, but this will work for 99% of most applications. Treating Unix/Linux/MacOS as "not Windows" covers nearly everything for x86, IA64, IA32e, and Mac PPC hardware -- maybe more. It's one thing to say "platform independance" but it usually means "Windows and some UNIX-like systems and maybe Netware and OS/2". Depends on what you want to run on.
Re: Platform independant directory separator
by Crian (Curate) on Mar 01, 2004 at 12:33 UTC
    I searched for a special perl var for your purpose without success.

    Perhaps the following fact will help you(?):

    You can use slash (in the most cases) as directory seperator under Windows systems too.

    But beside Unix/Linux and Windows I don't know what seperators are in use and if slash could be also used.
      What you actually mean is that the file system operations that Perl give you have had an inline tr!/!\\! added during the port to windows so that scripts written for UNIX will run OK. External commands only respect the backslash.
Re: Platform independant directory separator
by QwertyD (Pilgrim) on Mar 02, 2004 at 01:10 UTC

    While the suggestions of File::Spec are spot on, the module is not without its problems. Its functionality is fine. Its interface, on the other hand, (which somehow tries to be OO but isn't really) gives me a headache whenever I try to figure out how to use it.

    I reccomend Path::Class. It provides a much nicer object oriented interface that wraps the File::Spec functions underneath. It makes infinitely more sense, and is much more readable.


    Once it's Turing complete, everything else is just syntactic sugar.
Re: Platform independant directory separator
by coreolyn (Parson) on Mar 01, 2004 at 16:00 UTC

    This is going to be a lot more answer than you are looking for but as you are in a cross-platform situation I thought I'd share what I have found to be a very re-usable format. I'm in a situation where CPAN is difficult to utilize effectively in our organization, so I created a module I called OSify.pm. In it I created common OS commands OSrecursive copy, OSmkdir, etc and centralized their logic, It has made it so I can code for DOS, linux, and Solaris with the same commands easily, and can be quickly extended to other OS's as required. The following is just the OSPath() that takes care of the delimiter issue, but using the general approach it's easy to adapt to any given command.

    sub OSpath { $_ = $_[0]; debug( "Recieved path as\n $_\n", 0 ); if ( $^O =~ /mswin/i ) { # Everywhere you find a forward back slash replace it with # two backslashes if ( /(\/|\\\w)/ ) { s/(\/|\\)/\\\\/g; } # Incase we've created four backslashes in a row # reduceit back to one if ( /(\\)(\\)(\\)(\\)/ ) { s/\\\\\\\\/\\\\/g; } # Have to make sure there is only 1 slash after a drive letter if ( /(\:\\\\).*/ ) { s/$1/\:\\/; } } elsif ( $^O =~ /solaris/i ) { s/\\/\//g; if ( $_ =~ /.*\/(.*\s.*)\/.*/ ) { my $spacedDir = $1; unless ( $spacedDir =~ /"/ ) { $_ =~ s/$1/"$spacedDir"/g; } } } else { print "Platform $^O is not currently supported\n"; } debug( "Returning path as\n $_\n", 0 ); return $_; }

      File::Copy, File::Path, and File::Spec have been in the core for many years. Are there features they don't provide?

        I'm not saying there's not a better way to do it. It's just the way that's developed for me. The current list of functions in that module are:

        OSmkdir OSpath OSrmdir OSworkdir (Make a temp directory in $TEMP with unique name) OSlogger searchReplaceCopyFile printEnvVars debug getFileExt getEnvVars OScopy OSdelete singleDosDelim file2Array arrayRelevant getShortPath shortDirName (Dos 8 letter dirname) OSrecursiveCopy OSmkWritable
Re: Platform independant directory separator
by alg (Initiate) on Apr 19, 2023 at 02:08 UTC

    Before File::Spec, this is what I used. It still works today and it worked on very old perls on every Unix-like and Windows platforms that I've ever encountered.

    Basically, the idea is to ask perl what it uses as directory separator char.

    Sample use ($dirSep gets either back or forward slash character):

    $dirSep = ( $ENV{"PATH"} =~ m/;[a-z]:\\/i ) ? '\\' : '/' ; print $dirSep;
      Before File::Spec,

      so 26 years ago, why relevant today??