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

Trying to determine a cross-platform way of determining if a file path a user provides in a config file is absolute for the machine they are running the Perl code on. I'm not quite sure how to interpret the File::Spec documentation:

file_name_is_absolute Takes as its argument a path, and returns true if it is an absolute pa +th. $is_absolute = File::Spec->file_name_is_absolute( $path ); This does not consult the local filesystem on Unix, Win32, OS/2, or Ma +c OS (Classic). It does consult the working environment for VMS (see +file_name_is_absolute in File::Spec::VMS).

What does it mean when it says it does not "consult" the local filesystem? Will this function do what I need?

$PM = "Perl Monk's";
$MCF = "Most Clueless Friar Abbot Bishop Pontiff Deacon Curate Priest Vicar";
$nysus = $PM . ' ' . $MCF;
Click here if you love Perl Monks

Replies are listed 'Best First'.
Re: Determining if file path is absolute
by haukex (Archbishop) on Nov 03, 2018 at 22:03 UTC
    Will this function do what I need?

    The AM post already explained it pretty well: File::Spec generally just checks whether a string looks like an absolute pathname - it does not verify whether the file really exists or what its absolute pathname really is. For example, file_name_is_absolute("/tmp/../home") on a *NIX system will normally return true. If there is a symlink /tmp/badlink that points to a nonexistent location, file_name_is_absolute("/tmp/badlink") will still return true, because it looks like an absolute path. So if "what you need" is to determine whether a user entered something that looks like an absolute path, then yes, File::Spec is the right tool. (Note that File::Spec isn't completely "hands off" in terms of the filesystem in all of its functions, for example its rel2abs will use Cwd.)

    To do filename resolution that consults the file system (and does stuff like resolve symlinks), see abs_path from Cwd. (I took it a step further and implemented detailed symlink chain resolution (e.g. if you've got symlink1→symlink2→symlink3→target) in my relink tool - PM node on that.)

      OK, thanks for the additional clarification. I just need to verify that it looks like an absolute path. I was worried that the documentation was trying to say that if it looked like an absolute path on a local machine it might not look absolute on another machine.

      $PM = "Perl Monk's";
      $MCF = "Most Clueless Friar Abbot Bishop Pontiff Deacon Curate Priest Vicar";
      $nysus = $PM . ' ' . $MCF;
      Click here if you love Perl Monks

        I was worried that the documentation was trying to say that if it looked like an absolute path on a local machine it might not look absolute on another machine.

        You don't need to worry, unless those two machines are on different OSes, e.g. Windows vs. *NIX, since File::Spec loads the appropriate OS-specific module under the hood. On a *NIX system, it will say C:\\foo isn't absolute (on a Windows system, it'll still say /foo is absolute).

Re: Determining if file path is absolute
by Anonymous Monk on Nov 03, 2018 at 19:10 UTC

    File::Spec uses string operations to verify that a string looks like an absolute path (usually it's enough to just check what it starts with), but doesn't verify that such a file exists. On VMS, there is one more step:

    # If it's a logical name, expand it. $file = $ENV{$file} while $file =~ /^[\w\$\-]+\Z(?!\n)/s && $ENV{$file};
    I don't know enough VMS to understand why it is needed, but this is what the authors meant by "consult the working environment".

      I don't know enough VMS to understand why it is needed, but this is what the authors meant by "consult the working environment".
      Just to answer this question, although it might be slightly off-topic with respect to the original post.

      VMS is lavishly using logical names, which are more or less equivalent to environment variables on other operating systems, especially for directories. These logical names are automatically translated by the OS, so that you usually don't need explicit dereferencing using the %ENV hash.

      For example, the default login directory (equivalent of the $HOME environment variable under Unix or Linux) is SYS$LOGIN. On one of my VMS systems, my SYS$LOGIN default directory is defined as follows:

      show logical sys$login "SYS$LOGIN" = "DISK$WORK:[APPL.USER.ROL]" (LNM$JOB_89C65540)
      But the DISK$WORK disk is itself a logical name pointing toward a physical disk name:
      show logical disk$work "DISK$WORK" = "$2$DKC3:" (LNM$SYSTEM_TABLE)
      So, in the end, if you use the SYS$LOGIN path in a VMS (DCL) script or in a Perl program, it actually gets translated (in this case with a two-step process) into: $2$DKC3:[APPL.USER.ROL], which is effectively an absolute VMS path. Note that the first logical name (SYS$LOGIN) is defined at the process level (in the LNM$JOB_89C65540 job level logical table, i.e. when I log into the system) where as the second logical name (DISK$WORK) is defined at the system level (LNM$SYSTEM_TABLE, when the system is started). So the logical names form a kind of cascading levels of logical indirection. The example above has only two levels of indirection, but you can sometimes have three, four, or even more such levels of indirection.

      In VMS, you almost never directly use actual absolute paths (such as $2$DKC3:[APPL.USER.ROL]), but almost always logical names (such as SYS$LOGIN). So to determine whether a name finally corresponds to an absolute path, the File::Spec module has to unroll the cascade of logical name levels to find out whether, in the end, it corresponds to an actual alsolute path, in the form of a disk name (such as $2$DKC3:) followed by directory hierarchy tree (such as [APPL.USER.ROL] in the example above).

      The module only checks whether the logical name cascade finally unrolls to a string corresponding to a typical absolute path, it does not check whether the absolute path actually exists (just as it does not do that on a Unix system either).

Re: Determining if file path is absolute ( resolve realpath )
by Anonymous Monk on Nov 04, 2018 at 04:59 UTC
    use Path::Tiny qw/ path /; $foo = path( $foo )->realpath;