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

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?

This question is related to perl path location

The answer is


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__);

$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.


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

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


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";

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";

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.


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__ );


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__));

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.


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";

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


#!/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


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.


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

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.


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/;

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__);
}

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]

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));
}

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";

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 

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


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.


Questions with perl tag:

The program can't start because api-ms-win-crt-runtime-l1-1-0.dll is missing while starting Apache server on my computer "End of script output before headers" error in Apache Perl - Multiple condition if statement without duplicating code? How to decrypt hash stored by bcrypt Split a string into array in Perl Turning multiple lines into one comma separated line String compare in Perl with "eq" vs "==" how to remove the first two columns in a file using shell (awk, sed, whatever) Find everything between two XML tags with RegEx Difference between \w and \b regular expression meta characters Today's Date in Perl in MM/DD/YYYY format Best way to iterate through a Perl array Better way to remove specific characters from a Perl string The correct way to read a data file into an array Regex to match any character including new lines Search and replace a particular string in a file using Perl Grep to find item in Perl array Find size of an array in Perl Check whether a string contains a substring Perl - If string contains text? How to replace a string in an existing file in Perl? How to match a substring in a string, ignoring case Negative regex for Perl string pattern match How to print variables in Perl Why does modern Perl avoid UTF-8 by default? How to match any non white space character except a particular one? Escaping a forward slash in a regular expression Easy way to print Perl array? (with a little formatting) Submit form and stay on same page? How to use foreach with a hash reference? How to extract string following a pattern with grep, regex or perl How can I debug a Perl script? Rename Files and Directories (Add Prefix) Show a PDF files in users browser via PHP/Perl Perl regular expression (using a variable as a search string with Perl operator characters included) Perl: function to trim string leading and trailing whitespace What is the meaning of @_ in Perl? Perl read line by line How to see if a directory exists or not in Perl? How can I store the result of a system command in a Perl variable? How do I enter a multi-line comment in Perl? How do I update all my CPAN modules to their latest versions? Match whitespace but not newlines Perl: Use s/ (replace) and return new string In Perl, what is the difference between a .pm (Perl module) and .pl (Perl script) file? Array initialization in Perl How can I call a shell command in my Perl script? Programmatically read from STDIN or input file in Perl How to compile a Perl script to a Windows executable with Strawberry Perl? How do I search a Perl array for a matching string?

Questions with path tag:

Get Path from another app (WhatsApp) How to serve up images in Angular2? How to create multiple output paths in Webpack config Setting the correct PATH for Eclipse How to change the Jupyter start-up folder Setting up enviromental variables in Windows 10 to use java and javac How do I edit $PATH (.bash_profile) on OSX? Can't find SDK folder inside Android studio path, and SDK manager not opening Get the directory from a file path in java (android) Graphviz's executables are not found (Python 3.4) python: get directory two levels up importing go files in same folder res.sendFile absolute path How to place the ~/.composer/vendor/bin directory in your PATH? Windows 7 - Add Path Setting PATH environment variable in OSX permanently Set windows environment variables with a batch file Installing Python 2.7 on Windows 8 Writing File to Temp Folder Python: import module from another directory at the same level in project hierarchy Get real path from URI, Android KitKat new storage access framework nodejs get file name from absolute path? How can I troubleshoot Python "Could not find platform independent libraries <prefix>" How do I add to the Windows PATH variable using setx? Having weird problems ImportError: DLL load failed: %1 is not a valid Win32 application. But the DLL's are there what does it mean "(include_path='.:/usr/share/pear:/usr/share/php')"? Android Studio: Default project directory Display current path in terminal only Why am I getting a FileNotFoundError? Java - Find shortest path between 2 points in a distance weighted map How can I extract the folder path from file path in Python? Create a Path from String in Java7 Setting up Eclipse with JRE Path setting JAVA_HOME & CLASSPATH in CentOS 6 Apache - MySQL Service detected with wrong path. / Ports already in use Get current folder path Node.js check if path is file or directory Batch Extract path and filename from a variable Get java.nio.file.Path object from java.io.File Get file path of image on Android Where does Android app package gets installed on phone set pythonpath before import statements Python pip install module is not found. How to link python to pip location? Draw path between two points using Google Maps Android API v2 How to permanently set $PATH on Linux/Unix? How can I see the current value of my $PATH variable on OS X? How to get my project path? Where does Chrome store extensions? CSS Background Image Not Displaying How to get the Full file path from URI

Questions with location tag:

Nginx serves .php files as downloads, instead of executing them Get User's Current Location / Coordinates Location Services not working in iOS 8 How to set fake GPS location on IOS real device Android Google Maps API V2 Zoom to Current Location What is meaning of negative dbm in signal strength? How does it work - requestLocationUpdates() + LocationRequest/Listener How to get Android GPS location Redirect using AngularJS How to check if Location Services are enabled? Insert variable into Header Location PHP How to get complete address from latitude and longitude? Android: How to get accurate altitude? Get GPS location via a service in Android Calculating distance between two geographic locations Difference between window.location.href, window.location.replace and window.location.assign PHP header(Location: ...): Force URL change in address bar window.location.href and window.open () methods in JavaScript Android Location Providers - GPS or Network Provider? location.host vs location.hostname and cross-browser compatibility? ACCESS_FINE_LOCATION AndroidManifest Permissions Not Being Granted jquery: change the URL address without redirecting? Where does npm install packages? Algorithm to find all Latitude Longitude locations within a certain distance from a given Lat Lng location Calculate compass bearing / heading to location in Android Change window location Jquery What is the simplest and most robust way to get the user's current location on Android? How to mock location on device? What's the difference between window.location= and window.location.replace()? How do I get the current GPS location programmatically in Android? Where are include files stored - Ubuntu Linux, GCC Fastest Way to Find Distance Between Two Lat/Long Points Python + Django page redirect How do I get the full path to a Perl script that is executing?