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

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

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

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

任何人都有解决方案吗?


有几种方法:

  • $0是POSIX提供的当前正在执行的脚本,相对于当前工作目录(如果脚本位于CWD或以下)
  • 此外,Cwd模块提供了cwd()getcwd()abs_path(),并告诉您脚本从何处运行
  • 模块FindBin提供$Bin$RealBin变量,它们通常是执行脚本的路径。此模块还提供$Script$RealScript,它们是脚本的名称
  • __FILE__是Perl解释器在编译过程中要处理的实际文件,包括其完整路径。

我已经看到前三个($0Cwd模块和FindBin模块)在mod_perl下严重失败,产生了毫无价值的输出,例如'.'或空字符串。在这样的环境中,我使用__FILE__并使用File::Basename模块从中获取路径:

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

$ 0通常是程序的名称,那么这又如何呢?

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

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

更新对于几年后阅读的任何人,您都应该阅读Drew的答案。比我的好多了。


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

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


我认为您要查找的模块是FindBin:

1
2
3
4
5
6
#!/usr/bin/perl
use FindBin;

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

您可以使用FindBin,Cwd,File :: Basename或它们的组合。它们全部在Perl IIRC的基本发行版中。

我过去使用过Cwd:

Cwd:

1
2
3
4
use Cwd qw(abs_path);
my $path = abs_path($0);
print"$path\
"
;

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

FindBin试图做得更好,并在$PATH中徘徊,寻找与basename($0)相匹配的内容,但是有时候这会做得太令人惊讶了(特别是:当文件"就在您的面前"时)在cwd中。)

File::Fu为此具有File::Fu->program_nameFile::Fu->program_dir


一些简短的背景:

不幸的是,Unix API没有为运行的程序提供可执行文件的完整路径。实际上,执行您的程序可以在通常告诉您程序内容的字段中提供所需的内容。正如所有答案所指出的那样,有各种启发式方法可以找到可能的候选人。但是搜索整个文件系统总是可行的,即使移动或删除了可执行文件,即使这样也会失败。

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


你有没有尝试过:

1
$ENV{'SCRIPT_NAME'}

要么

1
2
3
use FindBin '$Bin';
print"The script is located in $Bin.\
"
;

它实际上取决于如何调用它,以及它是CGI还是从普通shell运行等。


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

1
2
3
4
5
6
7
#!/usr/bin/perl
use strict;
use warnings;
use File::Spec;
use File::Basename;

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

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

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

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


您在寻找这个吗?

1
2
3
4
5
6
my $thisfile = $1 if $0 =~
/\\\\([^\\\\]*)$|\\/([^\\/]*)$/;

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

输出将如下所示:

1
You are running MyFileName.pl now.

它在Windows和Unix上均可使用。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/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"\
$path\
"
;

:DD


在Windows上,同时使用dirnameabs_path对我来说效果最好。

1
2
3
4
5
6
7
8
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"\
dirname(abs_path(\\$0)) -> $abs_dirname\
"
;

原因如下:

1
2
3
4
5
6
7
8
9
# this gives the answer I want in relative path form, not absolute
my $rel_dirname = dirname(__FILE__);
print"dirname(__FILE__) -> $rel_dirname\
"
;

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

__FILE__的问题在于它将打印核心模块" .pm"路径,而不必打印正在运行的" .cgi"或" .pl"脚本路径。我想这取决于您的目标是什么。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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;

请添加任何建议。


没有任何对shell有效的外部模块,即使使用'../'也可以很好地工作:

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

测试:

1
2
3
4
5
6
7
8
$ /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

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

1
2
3
4
5
6
7
8
use File::Basename;
my $script_dir = undef;
if(-l __FILE__) {
  $script_dir = dirname(readlink(__FILE__));
}
else {
  $script_dir = dirname(__FILE__);
}

实际上,所有无库解决方案都无法通过多种方式来编写路径(请考虑../或/bla/x/../bin/./x/../等。我的解决方案看起来像我有一个怪癖:我不知道为什么我必须两次运行替换项,否则我会得到一个虚假的" ./"或" ../"。对我来说似乎很健壮。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  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/;

"最佳"答案都不适合我。使用FindBin'$ Bin'或Cwd的问题是它们返回了所有符号链接都已解析的绝对路径。在我的情况下,我需要带有符号链接的确切路径-与返回Unix命令" pwd"相同,而不是" pwd -P"。以下功能提供了解决方案:

1
2
3
4
5
6
7
8
9
10
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));
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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 \
" ;
        $ScriptAbsolutPath =~ m/^(.*)(\\\\|\\/)(.*)\\.([a-z]*)/;
        $RunDir = $1 ;
        #debug print"
\\$1 is $1 \
" ;
        #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 \
" ;
        return $ProductBaseDir ;
    } #eof sub

$^X怎么了?

1
2
3
#!/usr/bin/env perl
print"This is executed by $^X\
"
;

将为您提供正在使用的Perl二进制文件的完整路径。

翻转


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


推荐阅读

    linux执行多次命令?

    linux执行多次命令?,系统,信息,标准,工作,情况,命令,周期性,服务,代码,时间,l

    linux命令行显示路径?

    linux命令行显示路径?,系统,数据,信息,命令,工作,时间,标准,文件,目录,名称,l

    linux打断执行的命令?

    linux打断执行的命令?,系统,状态,网站,标准,通用,客服,人员,名字,网络,暂停,L

    linux脚本命令修改?

    linux脚本命令修改?,密码,系统,文件,资料,工具,软件,基础,地址,标准,命令,lin

    linux命令没执行完?

    linux命令没执行完?,系统,设备,工具,情况,密码,状态,电脑,管理,材料,服务,Lin

    linux命令引用文件名?

    linux命令引用文件名?,工作,系统,信息,命令,数据,文件,时间,灵活,名称,标准,l

    linux脚本命令教学?

    linux脚本命令教学?,标准,数据,系统,脚本,代码,流程,官网,底部,命令,变量,lin

    shell中执行linux命令?

    shell中执行linux命令?,系统,名称,环境,管理,工作,代码,技术,软件,经理,基础

    linux命令注释脚本?

    linux命令注释脚本?,代码,工具,名称,工作,脚本,发行,服务,环境,数据,基础,lin

    linux打印命令执行?

    linux打印命令执行?,信息,系统,工具,服务,命令,发行,基础,位置,设备,时间,怎

    脚本linux上运行命令?

    脚本linux上运行命令?,工具,代码,时间,密码,系统,环境,名字,位置,第三,下来,t

    linux执行两次命令?

    linux执行两次命令?,系统,信息,连续,名称,命令,初级,首页,工具,管理,终端,lin

    linux命令执行安装?

    linux命令执行安装?,软件,系统,管理,网站,官网,市场,中心,最新,灵活,工作,如

    linux中路径修改命令?

    linux中路径修改命令?,系统,命令,首次,工作,名称,目录,文件,环境变量,路径,

    linux执行一条新命令?

    linux执行一条新命令?,系统,工作,命令,管理,网络,服务,信息,目录,路径,脚本,L

    监控linux执行命令?

    监控linux执行命令?,系统,情况,数据,实时,网络,信息,状态,时间,设备,命令,如

    linux怎么看路径命令?

    linux怎么看路径命令?,数据,工作,系统,信息,时间,命令,文件,目录,路径,缩写,

    linux修改脚本的命令?

    linux修改脚本的命令?,系统,密码,服务,工作,工具,环境,信息,百度,代码,脚本,

    linux命令卡死不执行?

    linux命令卡死不执行?,系统,设备,数据,密码,工具,情况,软件,环境,分析,命令,l

    linux命令行路径补全?

    linux命令行路径补全?,系统,名称,软件,情况,命令,工具,智能,信息,不了,终端,l