web-dev-qa-db-ja.com

実行中のPerlスクリプトへのフルパスを取得するにはどうすればよいですか?

Perlスクリプトがあり、実行中にスクリプトの完全なパスとファイル名を決定する必要があります。スクリプトの呼び出し方法によって$0が異なり、fullpath+filenameが含まれることがあり、場合によってはfilenameだけが含まれることがあります。作業ディレクトリもさまざまなので、スクリプトのfullpath+filenameを確実に取得する方法は考えられません。

誰にも解決策がありますか?

161
Chris Madden

いくつかの方法があります:

  • $0 は、POSIXが提供する現在実行中のスクリプトであり、スクリプトがCWD以下である場合は、現在の作業ディレクトリに相対的です。
  • さらに、cwd()getcwd()、およびabs_path()Cwd モジュールによって提供され、スクリプトの実行元を示します
  • モジュール FindBin は、通常が実行スクリプトへのパスである$Binおよび$RealBin変数を提供します。このモジュールは、スクリプトの名前である$Script$RealScriptも提供します
  • __FILE__ は、Perlインタープリターがコンパイル中に処理する実際のファイルであり、その完全パスを含みます。

最初の3つ( $0Cwd モジュール、および FindBin モジュール)がmod_Perlの下で失敗し、'.'などの無意味な出力を生成するのを見てきましたまたは空の文字列。そのような環境では、 __FILE__ を使用し、 File::Basename モジュールを使用して、そこからパスを取得します。

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

通常、$ 0はプログラムの名前ですが、これはどうですか?

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

相対パスまたは絶対パスのどちらを使用しているかをabs_pathが認識しているため、これは機能するはずです。

Update今年以降読んでいる人は、 Drew's answer を読んでください。それは私のものよりもはるかに優れています。

143
Ovid
Use File::Spec;
File::Spec->rel2abs( __FILE__ );

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

34
Mark

お探しのモジュールはFindBinだと思います:

#!/usr/bin/Perl
use FindBin;

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

FindBinCwdFile :: Basename 、またはこれらの組み合わせを使用できます。それらはすべて、Perl IIRCの基本配布物に含まれています。

過去にCwdを使用しました。

Cwd:

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

$0または__FILE__への絶対パスを取得することが必要です。唯一の問題は、誰かがchdir()を実行し、$0が相対的だった場合です-驚きを防ぐために、BEGIN{}で絶対パスを取得する必要があります。

FindBinbasename($0)に一致するものを探して$PATHをより良くしようと試みますが、あまりにも驚くべきことを行う場合があります(具体的には、ファイルがcwdの「目の前」

File::Fuには、File::Fu->program_nameFile::Fu->program_dirがあります。

9
Eric Wilhelm

短い背景:

残念ながら、Unix APIは実行可能プログラムへの完全なパスを持つ実行中のプログラムを提供しません。実際、あなたのプログラムを実行するプログラムは、通常それが何であるかをあなたのプログラムに伝えるフィールドで何でも提供できます。すべての答えが指摘しているように、有望な候補を見つけるためのさまざまなヒューリスティックがあります。しかし、ファイルシステム全体を検索する以外に常に機能するものはなく、実行可能ファイルが移動または削除された場合でも失敗します。

ただし、実際に実行されているPerl実行可能ファイルは必要ありませんが、実行中のスクリプトは必要です。そして、Perlはスクリプトがそれを見つける場所を知る必要があります。これは__FILE__に保存されますが、$0はUnix APIからのものです。これは依然として相対パスである可能性があるため、Markの提案を受けて、File::Spec->rel2abs( __FILE__ );で正規化します

7
wnoise

スクリプトを含むディレクトリへのパスを取得するために、すでに与えられた回答の組み合わせを使用しました。

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

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

やってみました:

$ENV{'SCRIPT_NAME'}

または

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

呼び出される方法と、CGIか通常のシェルから実行されるかなどに大きく依存します。

6
Sean

perlfaq8 は、$0rel2abs()関数を使用して非常によく似た質問に答えます。この関数はFile :: Specにあります。

2
moritz

外部モジュールを使用する必要はありません。ファイル名と相対パスを指定できるのは1行だけです。モジュールを使用していて、スクリプトディレクトリへの相対パスを適用する必要がある場合は、相対パスで十分です。

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

これを探していますか?:

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

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

出力は次のようになります。

You are running MyFileName.pl now.

WindowsとUnixの両方で動作します。

1
Yong Li
#!/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

1
mkc
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 
0
Yordan Georgiev

「トップ」の答えはどれも私にとって適切ではありませんでした。 FindBin '$ Bin'またはCwdの使用に関する問題は、すべてのシンボリックリンクが解決された絶対パスを返すことです。私の場合、シンボリックリンクが存在する正確なパスが必要でした。これは、Unixコマンド「pwd -P」ではなく「pwd」を返すのと同じです。以下の機能が解決策を提供します。

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));
}
0
drjumper

dirname(__FILE__)を使用した場合の問題は、シンボリックリンクをたどらないことです。実際のファイルの場所へのシンボリックリンクをたどるには、スクリプトにこれを使用する必要がありました。

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

__FILE__の問題は、実行中の「.cgi」または「.pl」スクリプトパスではなく、コアモジュールの「.pm」パスを出力することです。私はあなたの目標が何であるかによると思います。

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;

提案を追加してください。

0
Jonathan

シェルに有効な外部モジュールがなくても、「../」でもうまく機能します。

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
0
Putnik

ライブラリを使用しないソリューションはすべて、パスを記述するいくつかの方法以外では実際には機能しません(../または/bla/x/../bin/./x/../などを考えてください。私のソリューションは奇妙な点が1つあります:置換を2回実行する必要がある理由がわかりません。そうしないと、偽の "./"または "../"が表示されます。それ以外は、私には非常に堅牢なようです。

  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
Elmar