如何获得正在执行的 Perl 脚本的完整路径?

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?

转载于:https://stackoverflow.com/questions/84932/how-do-i-get-the-full-path-to-a-perl-script-that-is-executing

21个回答

$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 below. It's much better than mine.

csdnceshi50
三生石@ did not expect to see -e appended to the path.
大约 3 年之前 回复
csdnceshi51
旧行李 When you execute a script inline (with -e), I believe perl creates a temp file to store your inline script. Looks like the location, in your case, is /tmp. What did you expect the result to be?
4 年多之前 回复
csdnceshi61
derek5. This worked fine for me under Windows 7. However, the path did not contain any links.
6 年多之前 回复
weixin_41568134
MAO-EYE Other problem I have: perl -e 'use Cwd "abs_path";print abs_path($0);' prints /tmp/-e
6 年多之前 回复
weixin_41568208
北城已荒凉 This reports an error "opendir(test.pl/..): is not a directory at test.pl line 8!
6 年多之前 回复
csdnceshi76
斗士狗 , did you report bug to Cwd module maintainer? It seems like Windows adoption bug.
6 年多之前 回复
csdnceshi80
胖鸭 wanted to add that there's a realpath, which is a synonym to abs_path, incase you prefer the no-underscore name
接近 8 年之前 回复
csdnceshi71
Memor.の Small comment, on activestate perl on windows $0 typically contains backslashes and abs_path returned forward slashes, so a quick "tr /\//\\/;" was needed to fix it.
大约 12 年之前 回复

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__);
weixin_41568183
零零乙 dirname is said to involve "quirks" in the Perl documentation, and it is recommended to use fileparse. So basically abs_path((fileparse(__FILE__))[1]) should give the path.
接近 2 年之前 回复
csdnceshi71
Memor.の So here is what worked for me, putting it all together with @Aftershock (thanks) to answer the original question. use Cwd 'abs_path'; use File::Basename; my $start; if ( -l __FILE__ ) { $start=dirname(readlink(__FILE__)); } else { $start=dirname(__FILE__); } my $fullpath = abs_path($start).'/'; my $filename= basename($start); print "$fullpath$filename";
大约 4 年之前 回复
csdnceshi55
~Onlooker Oh, this is so useful!! Thank you a lot!! ;)
4 年多之前 回复
csdnceshi65
larry*wei You can find when a module was first included in the standard modules with this incantation: perl -e 'use Module::CoreList; print Module::CoreList->first_release("File::Basename");'; echo. For File::Basename that was Perl 5.0.0, which was released in the late '90s—I think it's save to use by now.
4 年多之前 回复
csdnceshi55
~Onlooker How safe is it to use File::Basename;, meaning when this module started to be shipped with Perl core? Is it possible that some old Perl versions wouldn't have it. How to check it?
4 年多之前 回复
csdnceshi62
csdnceshi62 I have a script that's being run from another script using require 'script.pl' so $0 give me the path to the calling script, not the called one. __FILE__ gives the right answer in this case.
5 年多之前 回复
weixin_41568126
乱世@小熊 newbie here: although your solution worked (seeing as I could open files in that directory), is it normal that when I dd $dirname or print $dirname I get '.' as output?
大约 6 年之前 回复
csdnceshi78
程序go dirname(__FILE__) doesn't follow symlinks, so if you linked the executable file and where hoping to find the location of some other file in the install location you need to check if( -l __FILE__) and then dirname(readlink(__FILE__)).
6 年多之前 回复
csdnceshi80
胖鸭 Probably because the biggest recommendation from this answer (using dirname with __FILE__) doesn't work quite as expected? I end up with the relative path from where the script was executed, while the accepted answer gives me the full absolute path.
7 年多之前 回复
csdnceshi69
YaoRaoLov It looks like abs_path needs to be used with _____FILE_____ as it may contain the name only with the path.
7 年多之前 回复
csdnceshi67
bug^君 Upvote. Not really sure why this answer was not accepted as the above accepted answer is not functional considering it involves stripping the script name off the end of the path.
7 年多之前 回复
csdnceshi72
谁还没个明天 This is really the best solution, especially if you already have a modified $0
8 年多之前 回复
Use File::Spec;
File::Spec->rel2abs( __FILE__ );

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

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

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";
csdnceshi69
YaoRaoLov It does not provide the proper full path of the script if you run it like "./myscript.pl", as it would only show "." instead. But I still like this solution.
4 年多之前 回复

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

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.

csdnceshi71
Memor.の Bad idea because SCRIPT_NAME enviroment is depended on shell you are using. This is complete incompatibile with windows cmd.exe, and incompatibile when you call script directly from other binaries. There is no warranty this wariable is set. Above ways are much more usable.
6 年多之前 回复
csdnceshi77
狐狸.fox $ENV{'SCRIPT_NAME'} is empty when the script is running at console
6 年多之前 回复

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

weixin_41568183
零零乙 __FILE__ still gives me a relative path. i.e. '.'.
接近 4 年之前 回复

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

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.

csdnceshi76
斗士狗 Simply do all works based on current dir and $0 at the script begin.
6 年多之前 回复
csdnceshi80
胖鸭 Is it really likely that anyone would be so foolish as to (permanently) chdir() at compile time?
8 年多之前 回复
共21条数据 1 3 尾页
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问
相关内容推荐