Getting absolute path to perl executable for the current process - perl

Is there a way to get an absolute path to the Perl executable for the current process?
$^X will give me the Perl executable name, but the doc states that it will sometimes be a relative path, and this seems to be true on OS X for example.
ExtUtils::MakeMaker seems to have some magic to find the absolute path, since the Makefile it generates on my OS X contains
PERL = /usr/local/bin/perl
FULLPERL = /usr/local/bin/perl
but I have no idea how it does this or whether the magic is readily accessible to others.
EDIT: Thanks Borodin for the $Config{perlpath} tip. Grepping for this in ExtUtils, I found this tidbit in ExtUtils::MM_Unix::_fixin_replace_shebang, which I guess is what MakeMaker uses to replace #!perl with the correct shebang line.
if ( $Config{startperl} =~ m,^\#!.*/perl, ) {
$interpreter = $Config{startperl};
$interpreter =~ s,^\#!,,;
}
else {
$interpreter = $Config{perlpath};
}

I think what you're looking for is $Config{perlpath}.
If you want your code to be very portable you may have to append a file type to that value; this is described in the perlport documentation. Otherwise all you need is this:
use Config;
my $perl = $Config{perlpath};

You can get it via the core Config module.
use Config;
say $Config{perl5}; # current perl binary
I think that should always contain an absolute path, but I can't guarantee it.

Perl includes the core module File::Spec which can translate relative paths to absolute paths.
my $full_path_to_perl = File::Spec->rel2abs($^X);

For perl6 (raku): $*EXECUTABLE-NAME contains full path of the currently running Raku interpreter (like sys.executable for Python)
To get the full command line:
say ($*EXECUTABLE-NAME, $*PROGRAM-NAME, |#*ARGS).join(' ');
More in Variable Documentation

Related

Java's File.pathSeparator in Perl

Is there a module or constant somewhere in Perl that gives the equivalent of Java's File.pathSeparatorChar? I've been looking everywhere but the name easily brings up things like / and \, used to separate elements in a single path. I want the thing you use to separate values in an environment variable containing paths (: in Unix, ; in Windows, and I have no idea if there are others on other platforms).
I believe you are looking for $Config{path_sep}:
use Config;
print "path separator for $^O is '$Config{path_sep}'\n";
path separator for cygwin is ':'
(I found this be grepping for split.*PATH in the perl source code)
If you want to actually do anything with the system PATH variable, then you probably want the Env::Path module, but that indeed gets the value for the separator from $Config::Config{path_sep}.
Note that it is cleaner to use the Config module as
use Config ();
and then access the hash using the fully-qualified %Config::Config, as otherwise the module silently imports %Config into your current namespace.

How do I return absolute path names for files using Perl glob?

I have some Perl code which has file glob operation.
$file1 = #ARGV[0];
#res1 = glob "$file1*";
I want the whole absolute paths to be reflected when i glob the files, not just the file names which is the case currently in my code.
e.g. when I do glob "*.pdf" i need the absolute paths of the pdf files to be matched and returned to my array variable by glob.
I tried using module use File::Basename;
but that seems to be used for parsing a file path into directory, file name , suffix.
How do I get this effect.
thanks,
-AD.
You want to use the core module Cwd to get the full path with respect to your current working directory.
use Cwd;
#res1 = map { Cwd::abs_path($_) } glob "$file1*";
You want to use the standard module File::Spec. It has a sub, rel2abs() which is exactly what you want. See perldoc File::Spec for details. Also, see perldoc perlmodlib for the list of standard modules and pragmatics that are install along with Perl.

abs_path with the home directory

I created a perl script that uses abs_path but it doesn't correctly handle the home directory (represented by '~')
EG if I try to call abs_path("~/mystuff");
it returns undef
Can I make abs_path correctly handle the home directory? And if not, is there an alternative I can use?
#!/usr/bin/perl
use File::HomeDir;
print File::HomeDir->my_home;
The reason that abs_path doesn't handle it correctly is that "~" is a shell construct. Perl doesn't know anything about what "~" means - it literally treats it as "a directory named 'tilde'(~) under current working directory".
Any program to which "~" is supplied as a parameter would actually get a real directory path from shell instead.
To be able to use home directories from Perl, on Unix you can use $ENV{HOME} instead of "~" for your own home directory; or for other users use (getpwnam($user))[7]; there's no clean cross-platform way to do either.
A second approach is to use shell for dirty work in a system call:
my $expanded_home_dir = `cd ~/mydir/; pwd`;
UPDATE:
First, a very good recipe for outright replacement of tilde-home-strings is in "Perl Cookbook" (2d ed), ch. 7.3 "Expanding tildes in filenames".
Second, as daxim mentioned in comments, since Perl 5.6, CORE::glob() is actually automatically replaced with File::Glob::bsd_glob() which supports POSIX's GLOB_TILDE flag and therefore can expand tildes for you.
Interestingly enough, both bsd_glob (in C code, as per Perlmonks), and File::HomeDir mentioned wisely by Andrew Clark, use precisely the same logic underneath as the Cookbook's recipe 7.3 ($ENV{HOME}||$ENV{LOGDIR}||(getpwnam($<))[7]) for Unix environments.

What Perl module(s) do I use to obtain an absolute path (including filename) from a relative one on Windows?

I can only imagine I'm not searching correctly; this seems like an obvious question to be asked here. My apologies if this is a duplicate.
I'm writing a Perl program that will take a filename as a command-line argument. I need to convert the filename (or the filename with a relative path attached) to an absolute path (specifically to work with Win32::OLE).
I tried using Cwd's 'abs_path', and that almost does what I want, but it returns it using a Unix-style path instead of a Win32 one.
Is there a module that will convert the path, or perhaps a better module to use in the first place?
I use rel2abs from File::Spec. You have to be careful though: that might call getdcwd from Cwd, and it will assume that you want the current working directory for the current drive. If the file is on some other drive, you'll have to fix that up yourself or supply the second argument to set the base path.
use File::Spec::Functions qw(rel2abs);
print rel2abs($ARGV[0]), "\n";
my($foo) = abs_path($some_file);
$foo =~ s{/}{\\}g;
print "FOO: $foo\n";
I use Cwd's abs_path and then use a regex to convert the slashes when I really need it done. But I've found that for most uses, Unix-style slashes work just fine. It's only for the occasional "pass a filename to that annoyingly limited program" that I end up needing to convert the slashes.
use Cwd 'abs_path';
my $path = abs_path($rel_path);
# and only if necessary...
$path =~ s'[/\\]+'\\'g; # use Windows-style slashes
$path =~ s'^\\'\\\\'; # handle network path
But then.. I use a lot of network paths, with or without a mapped drive reference. Your mileage may vary.

Why doesn't "use lib" take effect in this way?

In my app, I put all the modules in one directory , let's just call it libx.
Since it's up to the user to choose where to deploy the app, I don't want to hardcode the lib path.
So at the beginning of myapp.pl, I wrote the following lines of code.
#! /usr/bin/perl -w
use strict;
my $curr_dir = $0;
my $curr_lib = $curr_dir;
$curr_lib =~ s/myapp\.pl/libx/;
use $curr_lib ;
Instead of getting what I'm expecting, I got compiling errors!
So what's wrong with my code? I don't want to hardcode the lib path when using use lib, how should I do this?
Sorry I forgot to mention that when the app is deployed, myapp.pl and libx are in the same directory.
use happens at compile-time, not run-time, so your variable hasn't been set yet.
You can do:
my $curr_lib;
BEGIN {
$curr_lib = $0;
$curr_lib =~ s/myapp\.pl/libx/;
}
use lib $curr_lib;
or you could:
use FindBin;
use lib "$FindBin::Bin/libx";
I had trouble with this before too. What's happening is that Perl makes two passes over your code: once to compile it, and the second time to run it. In you example, lines 4,5, and 6 don't execute until run time, but use takes effect during compile time.
One possibility is to put it all inside a BEGIN{} block, which will make the code execute at compile time. I've done this, but it's messy/ugly. (BTW, instead of $0, you need to use $ARGV[0] in Perl).
The best way to tell Perl where to pick up libraries is to use the -I flag. You can put it on the #! line, or if you are starting the script from another script, you can start it as
perl -I/your/directory/libx your_script.pl
You can use relative paths, so maybe
perl -I./libx script.pl
would work for you.
use xxx is a compile-time directive, not a run-time instruction. You cannot set it programmatically within the script you are running.
You may need to try require rather than use
If you need use, you need to set your $PERL5LIB environment variable to ensure your modules are correctly located and used, or change your shebang line to read #! /usr/local/perl -w -I/path/to/libx. There are other methods (local::lib etc.), but from your question it seems your control over installation is a bit limited for that sort of approach.