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

发布于 2024-07-04 08:46:40 字数 194 浏览 9 评论 0原文

我有 Perl 脚本,需要在执行期间确定脚本的完整路径和文件名。 我发现,根据您调用脚本的方式不同,$0 会有所不同,有时包含完整路径+文件名,有时仅包含文件名。 因为工作目录也可能有所不同,所以我想不出一种可靠地获取脚本的完整路径+文件名的方法。

有人有解决办法吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(23

娇妻 2024-07-11 08:46:40

您在寻找这个吗?:

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

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

输出将如下所示:

You are running MyFileName.pl now.

它适用于 Windows 和 Unix。

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.

我做我的改变 2024-07-11 08:46:40
#!/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

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

故事灯 2024-07-11 08:46:40

在 *nix 上,您可能有“whereis”命令,它会搜索您的 $PATH 查找具有给定名称的二进制文件。 如果 $0 不包含完整路径名,则运行 whereis $scriptname 并将结果保存到变量中应该会告诉您脚本所在的位置。

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.

请恋爱 2024-07-11 08:46:40

$0 通常是您的程序的名称,那么这个怎么样?

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

在我看来,这应该可以工作,因为 abs_path 知道您使用的是相对路径还是绝对路径。

更新对于任何年后阅读此书的人,您应该阅读德鲁的回答。 比我的好多了。

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

所谓喜欢 2024-07-11 08:46:40

无需使用外部模块,只需一行即可获得文件名和相对路径。 如果您正在使用模块并且需要应用相对于脚本目录的路径,则相对路径就足够了。

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

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";
风轻花落早 2024-07-11 08:46:40

perlfaq8 使用 rel2abs() 函数回答了一个非常相似的问题在 $0 上。 该函数可以在 File::Spec 中找到。

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

倾城花音 2024-07-11 08:46:40

为了获取包含我的脚本的目录的路径,我使用了已经给出的答案的组合。

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

my $dir = dirname(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__));
哥,最终变帅啦 2024-07-11 08:46:40

您是否尝试过:

$ENV{'SCRIPT_NAME'}

或者

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

这实际上取决于它的调用方式以及它是 CGI 还是从普通 shell 运行等。

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.

清音悠歌 2024-07-11 08:46:40

一些简短的背景知识:

不幸的是,Unix API 不提供正在运行的程序以及可执行文件的完整路径。 事实上,执行您的程序可以在通常告诉您的程序是什么的领域提供它想要的任何内容。 正如所有答案所指出的,有各种启发法来寻找可能的候选人。 但是,除了搜索整个文件系统之外,任何方法都可以正常工作,即使移动或删除了可执行文件,搜索也会失败。

但是您不需要实际运行的 Perl 可执行文件,而是它正在执行的脚本。 Perl 需要知道脚本在哪里才能找到它。 它将其存储在 __FILE__ 中,而 $0 来自 Unix API。 这仍然可以是相对路径,因此请采纳 Mark 的建议并使用 File::Spec->rel2abs( __FILE__ ); 对其进行规范化

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

无边思念无边月 2024-07-11 08:46:40

获取 $0__FILE__ 的绝对路径就是您想要的。 唯一的麻烦是,如果有人执行了 chdir() 并且 $0 是相对的 - 那么您需要在 BEGIN{} 以防止出现任何意外。

FindBin 试图做得更好,并在 $PATH 中寻找与 basename($0) 匹配的内容,但有时会出现这种情况太令人惊讶的事情(具体来说:当文件在 cwd 中“就在您面前”时。)

File::FuFile::Fu->program_nameFile::Fu->program_nameFile::Fu code> 和 File::Fu->program_dir 为此。

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.

小霸王臭丫头 2024-07-11 08:46:40

您可以使用FindBinCwd, File::Basename,或它们的组合。 它们都在 Perl IIRC 的基础发行版中。

我以前用过Cwd:

Cwd:

use Cwd qw(abs_path);
my $path = abs_path($0);
print "$path\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";
聆听风音 2024-07-11 08:46:40

没有任何外部模块,对 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

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
孤城病女 2024-07-11 08:46:40

__FILE__ 的问题是它会打印核心模块“.pm”路径,而不一定是正在运行的“.cgi”或“.pl”脚本路径。 我想这取决于你的目标是什么。

在我看来, Cwd 只需要更新了 mod_perl。 这是我的建议:

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;

请添加任何建议。

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.

深居我梦 2024-07-11 08:46:40

仅使用 dirname(__FILE__) 的问题是它不遵循符号链接。 我必须在我的脚本中使用它来跟踪符号链接到实际文件位置。

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

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__);
}
笨笨の傻瓜 2024-07-11 08:46:40
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 
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 
坚持沉默 2024-07-11 08:46:40

$^X 有什么问题吗?

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

将为您提供正在使用的 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

耀眼的星火 2024-07-11 08:46:40

所有无库解决方案实际上都不适用于多种编写路径的方法(想想 ../ 或 /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/;

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/;
你另情深 2024-07-11 08:46:40

“最重要”的答案都不适合我。 使用 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));
}

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));
}
放飞的风筝 2024-07-11 08:46:40

在 Windows 上,同时使用 dirnameabs_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";

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";
薄暮涼年 2024-07-11 08:46:40
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]
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]
瞳孔里扚悲伤 2024-07-11 08:46:40
use File::Spec;
File::Spec->rel2abs( __FILE__ );

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

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

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

情深已缘浅 2024-07-11 08:46:40

我认为您正在寻找的模块是 FindBin:

#!/usr/bin/perl
use FindBin;

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

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";
森林散布 2024-07-11 08:46:40

有几种方法:

  • $0 是当前正在执行的脚本由 POSIX 提供,如果脚本位于或低于 CWD,则相对于当前工作目录
  • 另外,cwd()getcwd()abs_path()Cwd 模块提供,并告诉您在哪里 运行,
  • 脚本从模块 FindBin 提供 $Bin & $RealBin 变量通常是执行脚本的路径; 该模块还提供了 $Script & $RealScript 是脚本的名称
  • __FILE__< /code>是 Perl 解释器在编译期间处理的实际文件,包括其完整路径。

我已经看过前三个($0,< a href="http://perldoc.perl.org/Cwd.html" rel="noreferrer">Cwd 模块和 FindBin 模块)在 mod_perl 下失败,产生毫无价值的输出,例如 '。 ' 或空字符串。 在这种环境中,我使用 __FILE__ 并获取使用 File::Basename 模块的路径:

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

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__);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文