How do I get the full path to a Perl script that is executing?

PerlPathLocation

Perl Problem Overview


I have Perl script and need to determine the full path and filename of the script during execution. I discovered that depending on how you call the script $0 varies and sometimes contains the fullpath+filename and sometimes just filename. Because the working directory can vary as well I can't think of a way to reliably get the fullpath+filename of the script.

Anyone got a solution?

Perl Solutions


Solution 1 - Perl

There are a few ways:

  • $0 is the currently executing script as provided by POSIX, relative to the current working directory if the script is at or below the CWD
  • Additionally, cwd(), getcwd() and abs_path() are provided by the Cwd module and tell you where the script is being run from
  • The module FindBin provides the $Bin & $RealBin variables that usually are the path to the executing script; this module also provides $Script & $RealScript that are the name of the script
  • __FILE__ is the actual file that the Perl interpreter deals with during compilation, including its full path.

I've seen the first three ($0, the Cwd module and the FindBin module) fail under mod_perl spectacularly, producing worthless output such as '.' or an empty string. In such environments, I use __FILE__ and get the path from that using the File::Basename module:

use File::Basename;
my $dirname = dirname(__FILE__);

Solution 2 - Perl

$0 is typically the name of your program, so how about this?

use Cwd 'abs_path';
print abs_path($0);

Seems to me that this should work as abs_path knows if you are using a relative or absolute path.

Update For anyone reading this years later, you should read Drew's answer. It's much better than mine.

Solution 3 - Perl

use File::Spec;
File::Spec->rel2abs( __FILE__ );

http://perldoc.perl.org/File/Spec/Unix.html

Solution 4 - Perl

I think the module you're looking for is FindBin:

#!/usr/bin/perl
use FindBin;

$0 = "stealth";
print "The actual path to this is: $FindBin::Bin/$FindBin::Script\n";

Solution 5 - Perl

You could use FindBin, Cwd, File::Basename, or a combination of them. They're all in the base distribution of Perl IIRC.

I used Cwd in the past:

Cwd:

use Cwd qw(abs_path);
my $path = abs_path($0);
print "$path\n";

Solution 6 - Perl

Getting the absolute path to $0 or __FILE__ is what you want. The only trouble is if someone did a chdir() and the $0 was relative -- then you need to get the absolute path in a BEGIN{} to prevent any surprises.

FindBin tries to go one better and grovel around in the $PATH for something matching the basename($0), but there are times when that does far-too-surprising things (specifically: when the file is "right in front of you" in the cwd.)

File::Fu has File::Fu->program_name and File::Fu->program_dir for this.

Solution 7 - Perl

Some short background:

Unfortunately the Unix API doesn't provide a running program with the full path to the executable. In fact, the program executing yours can provide whatever it wants in the field that normally tells your program what it is. There are, as all the answers point out, various heuristics for finding likely candidates. But nothing short of searching the entire filesystem will always work, and even that will fail if the executable is moved or removed.

But you don't want the Perl executable, which is what's actually running, but the script it is executing. And Perl needs to know where the script is to find it. It stores this in __FILE__, while $0 is from the Unix API. This can still be a relative path, so take Mark's suggestion and canonize it with File::Spec->rel2abs( __FILE__ );

Solution 8 - Perl

Have you tried:

$ENV{'SCRIPT_NAME'}

or

use FindBin '$Bin';
print "The script is located in $Bin.\n";

It really depends on how it's being called and if it's CGI or being run from a normal shell, etc.

Solution 9 - Perl

In order to get the path to the directory containing my script I used a combination of answers given already.

#!/usr/bin/perl
use strict;
use warnings;
use File::Spec;
use File::Basename;

my $dir = dirname(File::Spec->rel2abs(__FILE__));

Solution 10 - Perl

perlfaq8 answers a very similar question with using the rel2abs() function on $0. That function can be found in File::Spec.

Solution 11 - Perl

There's no need to use external modules, with just one line you can have the file name and relative path. If you are using modules and need to apply a path relative to the script directory, the relative path is enough.

$0 =~ m/(.+)[\/\\](.+)$/;
print "full path: $1, file name: $2\n";

Solution 12 - Perl

Are you looking for this?:

my $thisfile = $1 if $0 =~
/\\([^\\]*)$|\/([^\/]*)$/;

print "You are running $thisfile
now.\n";

The output will look like this:

You are running MyFileName.pl now.

It works on both Windows and Unix.

Solution 13 - Perl

#!/usr/bin/perl -w
use strict;


my $path = $0;
$path =~ s/\.\///g;
if ($path =~ /\//){
  if ($path =~ /^\//){
    $path =~ /^((\/[^\/]+){1,}\/)[^\/]+$/;
    $path = $1;
    }
  else {
    $path =~ /^(([^\/]+\/){1,})[^\/]+$/;
    my $path_b = $1;
    my $path_a = `pwd`;
    chop($path_a);
    $path = $path_a."/".$path_b;
    }
  }
else{
  $path = `pwd`;
  chop($path);
  $path.="/";
  }
$path =~ s/\/\//\//g;



print "\n$path\n";

:DD

Solution 14 - Perl

The problem with just using dirname(__FILE__) is that it doesn't follow symlinks. I had to use this for my script to follow the symlink to the actual file location.

use File::Basename;
my $script_dir = undef;
if(-l __FILE__) {
  $script_dir = dirname(readlink(__FILE__));
}
else {
  $script_dir = dirname(__FILE__);
}

Solution 15 - Perl

use strict ; use warnings ; use Cwd 'abs_path';
	sub ResolveMyProductBaseDir { 

		# Start - Resolve the ProductBaseDir
		#resolve the run dir where this scripts is placed
		my $ScriptAbsolutPath = abs_path($0) ; 
		#debug print "\$ScriptAbsolutPath is $ScriptAbsolutPath \n" ;
		$ScriptAbsolutPath =~ m/^(.*)(\\|\/)(.*)\.([a-z]*)/; 
		$RunDir = $1 ; 
		#debug print "\$1 is $1 \n" ;
		#change the \'s to /'s if we are on Windows
		$RunDir =~s/\\/\//gi ; 
		my @DirParts = split ('/' , $RunDir) ; 
		for (my $count=0; $count < 4; $count++)	{ 	pop @DirParts ;  	}
		my $ProductBaseDir = join ( '/' , @DirParts ) ; 
		# Stop - Resolve the ProductBaseDir
		#debug print "ResolveMyProductBaseDir $ProductBaseDir is $ProductBaseDir \n" ; 
		return $ProductBaseDir ; 
	} #eof sub 

Solution 16 - Perl

The problem with __FILE__ is that it will print the core module ".pm" path not necessarily the ".cgi" or ".pl" script path that is running. I guess it depends on what your goal is.

It seems to me that Cwd just needs to be updated for mod_perl. Here is my suggestion:

my $path;

use File::Basename;
my $file = basename($ENV{SCRIPT_NAME});

if (exists $ENV{MOD_PERL} && ($ENV{MOD_PERL_API_VERSION} < 2)) {
  if ($^O =~/Win/) {
    $path = `echo %cd%`;
    chop $path;
    $path =~ s!\\!/!g;
    $path .= $ENV{SCRIPT_NAME};
  }
  else {
    $path = `pwd`;
    $path .= "/$file";
  }
  # add support for other operating systems
}
else {
  require Cwd;
  $path = Cwd::getcwd()."/$file";
}
print $path;

Please add any suggestions.

Solution 17 - Perl

Without any external modules, valid for shell, works well even with '../':

my $self = `pwd`;
chomp $self;
$self .='/'.$1 if $0 =~/([^\/]*)$/; #keep the filename only
print "self=$self\n";

test:

$ /my/temp/Host$ perl ./host-mod.pl 
self=/my/temp/Host/host-mod.pl

$ /my/temp/Host$ ./host-mod.pl 
self=/my/temp/Host/host-mod.pl

$ /my/temp/Host$ ../Host/./host-mod.pl 
self=/my/temp/Host/host-mod.pl

Solution 18 - Perl

All the library-free solutions don't actually work for more than a few ways to write a path (think ../ or /bla/x/../bin/./x/../ etc. My solution looks like below. I have one quirk: I don't have the faintest idea why I have to run the replacements twice. If I don't, I get a spurious "./" or "../". Apart from that, it seems quite robust to me.

  my $callpath = $0;
  my $pwd = `pwd`; chomp($pwd);

  # if called relative -> add pwd in front
  if ($callpath !~ /^\//) { $callpath = $pwd."/".$callpath; }  

  # do the cleanup
  $callpath =~ s!^\./!!;                          # starts with ./ -> drop
  $callpath =~ s!/\./!/!g;                        # /./ -> /
  $callpath =~ s!/\./!/!g;                        # /./ -> /        (twice)

  $callpath =~ s!/[^/]+/\.\./!/!g;                # /xxx/../ -> /
  $callpath =~ s!/[^/]+/\.\./!/!g;                # /xxx/../ -> /   (twice)

  my $calldir = $callpath;
  $calldir =~ s/(.*)\/([^\/]+)/$1/;

Solution 19 - Perl

None of the "top" answers were right for me. The problem with using FindBin '$Bin' or Cwd is that they return absolute path with all symbolic links resolved. In my case I needed the exact path with symbolic links present - the same as returns Unix command "pwd" and not "pwd -P". The following function provides the solution:

sub get_script_full_path {
    use File::Basename;
    use File::Spec;
    use Cwd qw(chdir cwd);
    my $curr_dir = cwd();
    chdir(dirname($0));
    my $dir = $ENV{PWD};
    chdir( $curr_dir);
    return File::Spec->catfile($dir, basename($0));
}

Solution 20 - Perl

On Windows using dirname and abs_path together worked best for me.

use File::Basename;
use Cwd qw(abs_path);

# absolute path of the directory containing the executing script
my $abs_dirname = dirname(abs_path($0));
print "\ndirname(abs_path(\$0)) -> $abs_dirname\n";

here's why:

# this gives the answer I want in relative path form, not absolute
my $rel_dirname = dirname(__FILE__); 
print "dirname(__FILE__) -> $rel_dirname\n"; 

# this gives the slightly wrong answer, but in the form I want 
my $full_filepath = abs_path($0);
print "abs_path(\$0) -> $full_filepath\n";

Solution 21 - Perl

use File::Basename;
use Cwd 'abs_path';
print dirname(abs_path(__FILE__)) ;

Drew's answer gave me:

'.'

$ cat >testdirname
use File::Basename;
print dirname(__FILE__);
$ perl testdirname
.$ perl -v

This is perl 5, version 28, subversion 1 (v5.28.1) built for x86_64-linux-gnu-thread-multi][1]

Solution 22 - Perl

What's wrong with $^X ?

#!/usr/bin/env perl<br>
print "This is executed by $^X\n";

Would give you the full path to the Perl binary being used.

Evert

Solution 23 - Perl

On *nix, you likely have the "whereis" command, which searches your $PATH looking for a binary with a given name. If $0 doesn't contain the full path name, running whereis $scriptname and saving the result into a variable should tell you where the script is located.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionChris MaddenView Question on Stackoverflow
Solution 1 - PerlDrew StephensView Answer on Stackoverflow
Solution 2 - PerlOvidView Answer on Stackoverflow
Solution 3 - PerlMarkView Answer on Stackoverflow
Solution 4 - PerlbmdhacksView Answer on Stackoverflow
Solution 5 - PerlBenjamin W. SmithView Answer on Stackoverflow
Solution 6 - PerlEric WilhelmView Answer on Stackoverflow
Solution 7 - PerlwnoiseView Answer on Stackoverflow
Solution 8 - PerlSeanView Answer on Stackoverflow
Solution 9 - PerlMattView Answer on Stackoverflow
Solution 10 - PerlmoritzView Answer on Stackoverflow
Solution 11 - Perldaniel souzaView Answer on Stackoverflow
Solution 12 - PerlYong LiView Answer on Stackoverflow
Solution 13 - PerlmkcView Answer on Stackoverflow
Solution 14 - PerlDavidGambaView Answer on Stackoverflow
Solution 15 - PerlYordan GeorgievView Answer on Stackoverflow
Solution 16 - PerlJonathanView Answer on Stackoverflow
Solution 17 - PerlPutnikView Answer on Stackoverflow
Solution 18 - PerlElmarView Answer on Stackoverflow
Solution 19 - PerldrjumperView Answer on Stackoverflow
Solution 20 - Perluser3228609View Answer on Stackoverflow
Solution 21 - Perluser3673View Answer on Stackoverflow
Solution 22 - Perluser3061015View Answer on Stackoverflow
Solution 23 - PerlfoxxtrotView Answer on Stackoverflow