use用法 - perl模組




我如何獲得正在執行的Perl腳本的完整路徑? (14)

我有Perl腳本,需要在執行過程中確定腳本的完整路徑和文件名。 我發現取決於你如何調用腳本$0變化,有時包含fullpath+filename ,有時只是filename 。 因為工作目錄可能會有所不同,所以我想不出一種可靠地獲取腳本的fullpath+filename的方法。

任何人都有解決方案?


$ 0通常是您程序的名稱,那麼如何?

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

在我看來,這應該工作,因為abs_path知道你是否使用相對或絕對路徑。

更新對於任何閱讀這些年後的人,你應該閱讀德魯的答案。 這比我的好多了。


perlfaq8使用$0上的rel2abs()函數回答了一個非常類似的問題。 該功能可以在File :: Spec中找到。


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

請添加任何建議。


一些簡短的背景:

不幸的是,Unix API並沒有提供一個正在運行的程序和可執行文件的完整路徑。 事實上,執行你的程序可以在該領域提供任何想要的東西,通常會告訴程序它是什麼。 正如所有答案指出的那樣,有各種啟發式方法來尋找可能的候選人。 但是,搜索整個文件系統的任何工作都不會總是有效,甚至如果可執行文件被移動或刪除,那也將失敗。

但是你不希望Perl的可執行文件,這是實際運行的,而是它正在執行的腳本。 Perl需要知道腳本在哪裡找到它。 它存儲在__FILE__ ,而$0來自Unix API。 這仍然可以是一個相對路徑,所以請參考Mark的建議並使用File::Spec->rel2abs( __FILE__ );對其進行標記File::Spec->rel2abs( __FILE__ );


你在找這個嗎?:

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

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

輸出將如下所示:

You are running MyFileName.pl now.

它適用於Windows和Unix。


你有沒有嘗試過:

$ENV{'SCRIPT_NAME'}

要么

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

這實際上取決於它如何被調用,以及它是CGI還是正常shell運行等。


在* nix上,您可能有“whereis”命令,它會搜索您的$ PATH以查找具有給定名稱的二進製文件。 如果$ 0不包含完整的路徑名,那麼運行whereis $ scriptname並將結果保存到變量中會告訴您腳本的位置。


您可以使用FindBinCwdFile::Basename或它們的組合。 他們都在Perl IIRC的基礎版本中。

我過去使用過Cwd:

CWD:

use Cwd qw(abs_path);
my $path = abs_path($0);
print "$path\n";

所有無庫的解決方案實際上並不僅僅可以用於編寫路徑的幾種方式(想想../或/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/;

有幾種方法:

  • $0是POSIX提供的當前正在執行的腳本,相對於當前工作目錄(如果腳本處於或低於CWD)
  • 此外, cwd()getcwd()abs_path()Cwd模塊提供,並告訴您腳本從哪裡運行
  • 模塊FindBin提供$Bin$RealBin變量, $RealBin變量通常是執行腳本的路徑; 該模塊還提供$Script的名稱$Script$RealScript
  • __FILE__是Perl解釋器在編譯期間處理的實際文件,包括其完整路徑。

我已經看到前三個( $0Cwd模塊和FindBin模塊)在mod_perl下失敗,產生無價值的輸出,例如'.' 或者一個空字符串。 在這樣的環境中,我使用__FILE__並使用File::Basename模塊獲取路徑:

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

為了獲得包含腳本的目錄的路徑,我使用了已經給出的答案的組合。

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

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

獲取絕對路徑為$0__FILE__是你想要的。 唯一的麻煩是如果有人做了chdir()$0是相對的 - 那麼你需要在BEGIN{}獲取絕對路徑,以防止出現任何意外。

FindBin試圖更好地在$PATH尋找匹配basename($0) ,但是有時候這會做出太令人驚訝的事情(特別是:當文件“在你的前面”時順時針。)

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



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 




location