我有Perl脚本,需要在执行期间确定脚本的完整路径和文件名。我发现根据您调用脚本$0
的方式而有所不同,有时包含fullpath+filename
,有时只包含filename
。因为工作目录也可能有所不同,所以我想不出可靠地获取脚本fullpath+filename
的方法。
有人有解决方案吗?
答案 0 :(得分:228)
有几种方法:
$0
是POSIX提供的当前正在执行的脚本,如果脚本位于或低于CWD,则相对于当前工作目录cwd()
模块提供了getcwd()
,abs_path()
和$Bin
,并告诉您脚本的运行位置Cwd
提供$RealBin
& 通常的$Script
个变量是执行脚本的路径;该模块还提供$RealScript
& mod_perl
这是脚本的名称FindBin
是Perl解释器在编译期间处理的实际文件,包括其完整路径。我看到前三个(__FILE__
,$0
模块和Cwd
模块)在'.'
下失败,产生了无价值的输出,例如{{1或一个空字符串。在这样的环境中,我使用FindBin
并使用__FILE__
模块从中获取路径:
use File::Basename;
my $dirname = dirname(__FILE__);
答案 1 :(得分:143)
$ 0通常是您的程序的名称,那么这个怎么样?
use Cwd 'abs_path';
print abs_path($0);
对我来说,这应该有效,因为abs_path知道你是使用相对路径还是绝对路径。
更新对于今年阅读的人,您应该阅读以下Drew的回答。它比我的要好得多。
答案 2 :(得分:34)
Use File::Spec;
File::Spec->rel2abs( __FILE__ );
答案 3 :(得分:16)
我认为您正在寻找的模块是FindBin:
#!/usr/bin/perl
use FindBin;
$0 = "stealth";
print "The actual path to this is: $FindBin::Bin/$FindBin::Script\n";
答案 4 :(得分:11)
您可以使用FindBin,Cwd,File::Basename或其组合。它们都在Perl IIRC的基础版本中。
我过去使用过Cwd:
CWD:
use Cwd qw(abs_path);
my $path = abs_path($0);
print "$path\n";
答案 5 :(得分:9)
获取$0
或__FILE__
的绝对路径是您想要的。唯一的麻烦是如果有人做了chdir()
并且$0
是相对的 - 那么你需要在BEGIN{}
中获得绝对路径以防止任何意外。
FindBin
试图更好地在$PATH
中找到与basename($0)
相匹配的东西,但有时会发生太令人惊讶的事情(特别是: cwd中的文件“就在你面前”。)
File::Fu
有File::Fu->program_name
和File::Fu->program_dir
。
答案 6 :(得分:7)
一些简短的背景:
不幸的是,Unix API没有为正在运行的程序提供可执行文件的完整路径。事实上,执行你的程序可以在字段中提供它想要的任何东西,通常告诉你的程序它是什么。正如所有答案所指出的那样,有各种启发式方法可以找到可能的候选人。但是,搜索整个文件系统总是有效的,如果移动或删除可执行文件,即使这样也会失败。
但是你不想要Perl可执行文件,它实际上正在运行,但是它正在执行的脚本。 Perl需要知道脚本在哪里找到它。它将其存储在__FILE__
中,而$0
来自Unix API。这仍然是一个相对路径,因此请采用Mark的建议并使用File::Spec->rel2abs( __FILE__ );
答案 7 :(得分:6)
你试过了吗?
$ENV{'SCRIPT_NAME'}
或
use FindBin '$Bin';
print "The script is located in $Bin.\n";
这实际上取决于它是如何调用的,如果它是CGI还是从普通的shell运行等等。
答案 8 :(得分:6)
为了获得包含我的脚本的目录的路径,我使用了已经给出的答案组合。
#!/usr/bin/perl
use strict;
use warnings;
use File::Spec;
use File::Basename;
my $dir = dirname(File::Spec->rel2abs(__FILE__));
答案 9 :(得分:2)
perlfaq8使用rel2abs()
上的$0
函数回答了一个非常类似的问题。该函数可以在File :: Spec。
答案 10 :(得分:2)
不需要使用外部模块,只需一行就可以获得文件名和相对路径。如果您正在使用模块并且需要应用相对于脚本目录的路径,则相对路径就足够了。
$0 =~ m/(.+)[\/\\](.+)$/;
print "full path: $1, file name: $2\n";
答案 11 :(得分:1)
你在找这个吗?:
my $thisfile = $1 if $0 =~
/\\([^\\]*)$|\/([^\/]*)$/;
print "You are running $thisfile
now.\n";
输出将如下所示:
You are running MyFileName.pl now.
它适用于Windows和Unix。
答案 12 :(得分:1)
#!/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
答案 13 :(得分:0)
use File::Basename;
use Cwd 'abs_path';
print dirname(abs_path(__FILE__)) ;
'。'
$ 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]
答案 14 :(得分:0)
在Windows上同时使用dirname
和abs_path
对我来说效果最好。
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";
原因如下:
# 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";
答案 15 :(得分:0)
“最佳”答案都不适合我。使用FindBin'$ Bin'或Cwd的问题是它们返回了所有符号链接都已解析的绝对路径。在我的情况下,我需要带有符号链接的确切路径-与返回Unix命令“ pwd”相同,而不是“ pwd -P”。以下功能提供了解决方案:
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));
}
答案 16 :(得分:0)
所有免费的解决方案实际上并不适用于编写路径的几种方法(想想../或/bla/x/../bin/./x/../等我的解决方案如下所示。我有一个怪癖:我不知道为什么我必须两次运行替换。如果我不这样做,我会得到一个虚假的“./”或“../”。那对我来说似乎很健壮。
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/;
答案 17 :(得分:0)
仅使用dirname(__FILE__)
的问题在于它没有遵循符号链接。我不得不使用这个脚本来跟踪符号链接到实际的文件位置。
use File::Basename;
my $script_dir = undef;
if(-l __FILE__) {
$script_dir = dirname(readlink(__FILE__));
}
else {
$script_dir = dirname(__FILE__);
}
答案 18 :(得分:0)
没有任何外部模块,对shell有效,即使使用'../':
也能正常工作my $self = `pwd`;
chomp $self;
$self .='/'.$1 if $0 =~/([^\/]*)$/; #keep the filename only
print "self=$self\n";
试验:
$ /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
答案 19 :(得分:0)
__FILE__
的问题是它将打印核心模块“.pm”路径,而不一定是正在运行的“.cgi”或“.pl”脚本路径。我想这取决于你的目标是什么。
在我看来,只需要为mod_perl更新Cwd
。这是我的建议:
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;
请添加任何建议。
答案 20 :(得分:0)
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
答案 21 :(得分:-1)
$^X
出了什么问题?
#!/usr/bin/env perl<br>
print "This is executed by $^X\n";
将为您提供所使用的Perl二进制文件的完整路径。
埃弗特
答案 22 :(得分:-5)
在* nix上,您可能有“whereis”命令,它会搜索$ PATH以查找具有给定名称的二进制文件。如果$ 0不包含完整路径名,则运行whereis $ scriptname并将结果保存到变量中应该告诉您脚本的位置。