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


168

Perlスクリプトがあり、実行中にスクリプトの完全パスとファイル名を特定する必要があります。スクリプトの呼び出し方によって異なり、スクリプト$0が含まれているfullpath+filenameこともあれば、単に含まれていることもありfilenameます。作業ディレクトリも変化する可能性があるため、確実に取得する方法は考えられませんfullpath+filename、スクリプト。

誰かが解決策を手に入れましたか?

回答:


251

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

  • $0 スクリプトがCWD以下の場合、現在の作業ディレクトリを基準にした、POSIXによって提供される現在実行中のスクリプトです。
  • また、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__);

2
これは、特に変更済みの$ 0がある場合は特に最良の解決策です
Caterham

8
abs_pathは、_____ FILE_____で使用する必要があるように見えます。これは、パスのみの名前を含む可能性があるためです。
余震2013年

6
@vicTROLLAおそらくこの回答からの最大の推奨事項(dirnameをで使用__FILE__)が期待どおりに機能しないためでしょうか?結局、スクリプトが実行された場所からの相対パスになりますが、受け入れられた答えは完全な絶対パスを示します。
イズカタ

10
dirname(__FILE__)はシンボリックリンクをたどらないので、実行可能ファイルをリンクし、インストール場所にある他のファイルの場所を見つけたい場合は、確認if( -l __FILE__)してからを実行する必要がありますdirname(readlink(__FILE__))
DavidG 2014

3
@IliaRostovtsevモジュールがこの呪文で標準モジュールに最初に含まれたのはいつかがわかりますperl -e 'use Module::CoreList; print Module::CoreList->first_release("File::Basename");'; echo。以下のためにFile::Basenameその90年代後半-私はそれが今では使用に保存することだと思うにリリースされたのPerl 5.0.0、でした。
Drew Stephens

145

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

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

これは、abs_pathが相対パスと絶対パスのどちらを使用しているかを知っているので、これで機能するはずです。

更新今年後に読む人は、Drewの回答を読んでください。それは私のものよりはるかに優れています。


11
ウィンドウ$ 0のactivestate perlに関する小さなコメントには、通常、バックスラッシュとabs_pathが返すスラッシュが含まれているため、簡単に "tr / \ // \\ /;"と表示されます。それを修正するために必要でした
Chris Madden

3
あることを追加したいrealpath、と同義語であるabs_path、あなたはノーアンダースコアの名前を好む包み
vol7ron

@Chris、Cwdモジュールのメンテナにバグを報告しましたか?Windows採用のバグのようです。
Znik

1
私が抱えているその他の問題:perl -e 'use Cwd "abs_path";print abs_path($0);' 版画/tmp/-e
レオンブロイ、2014年

2
@leonbloy(-e)を使用してインラインでスクリプトを実行すると、perlはインラインスクリプトを格納するための一時ファイルを作成すると思います。あなたの場合、場所はのようです/tmp。結果はどうなると思いましたか?
GreenGiant


16

私が探しているモジュールはFindBinだと思います:

#!/usr/bin/perl
use FindBin;

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

11

FindBinCwdFile :: Basenameを使用できます、またはそれらの組み合わせを。これらはすべて、Perl IIRCの基本ディストリビューションに含まれています。

私は過去にCwdを使用しました:

Cwd:

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

@bmdhacks、あなたは正しい。推定では、0 $を変更しませんでした。たとえば、スクリプトが開始するとすぐに(初期化ブロックで)、または$ 0を変更しない場合は他の場所で作業します。しかし、$ 0は 'ps' unixツールの下に表示されるプロセスの説明を変更する優れた方法です:)これは現在のプロセスのステータスなどを示すことができます。これはプログラマの目的に依存します:)
Znik

9

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

FindBinは、に$PATH一致するものを1つ上手に探して、でうろうろしますがbasename($0)、それがあまりにも驚くべきことを行う場合があります(特に、ファイルがcwdの「目の前」にある場合)。

File::Fuこれを持っFile::Fu->program_nameFile::Fu->program_dirいます。


chdir()コンパイル時に(永久に)誰もが愚かにする可能性は本当にありますか?
SamB

スクリプトの開始時に、現在のディレクトリと$ 0に基づいてすべての作業を行うだけです。
Znik

7

短い背景:

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

しかし、実際に実行されているPerl実行可能ファイルではなく、実行中のスクリプトが必要です。そして、Perlはスクリプトがどこにあるかを知る必要があります。それは、これを保存し__FILE__ながら、$0UnixのAPIからです。これはまだ相対パスである可能性があるため、Markの提案に従って、次のように正規化します。File::Spec->rel2abs( __FILE__ );


__FILE__それでも私に相対パスを与えます。つまり、「。」。
felwithe

6

やってみました:

$ENV{'SCRIPT_NAME'}

または

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

それはそれがどのように呼び出されているか、それがCGIであるか、通常のシェルから実行されているかなどに本当に依存します。


スクリプトがコンソールで実行されている場合、$ ENV {'SCRIPT_NAME'}は空です
Putnik

SCRIPT_NAME環境は使用しているシェルに依存しているため、悪い考えです。これは、windows cmd.exeと完全に互換性がなく、他のバイナリからスクリプトを直接呼び出すと互換性がなくなります。このwariableが設定されている保証はありません。上記の方法ははるかに便利です。
Znik

6

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

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

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

2

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


2

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

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

「./myscript.pl」のように実行すると、「。」しか表示されないため、スクリプトの適切な完全パスが提供されません。代わりに。しかし、私はまだこのソリューションが好きです。
2016年

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


4
コードだけで答えないでください。これが正しい答えである理由を説明してください。
Lee Taylor、

1

これをお探しですか?:

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

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

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

You are running MyFileName.pl now.

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


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 

ソースのみの回答はユーザーの質問を解決する可能性がありますが、それが機能する理由を理解するのに役立ちません。あなたはユーザーに魚を与えましたが、代わりに彼らに釣り方を教えるべきです。
Tin Man

0

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

Cwdmod_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

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

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

symlinkを呼び出すとどうなりますか?Cwdはこのケースでうまく機能します。
Znik

0

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

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

0

ライブラリを使用しないすべてのソリューションは、パスを書き込むためのいくつかの方法(../または/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

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

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

-2

何が問題になってい$^Xますか?

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

使用されているPerlバイナリへの完全なパスを提供します。

エバート


1
必要なスクリプトへのパスとPerlバイナリへのパスを提供します
Putnik

-5

* nixでは、おそらく「whereis」コマンドがあり、これは$ PATHを検索して、指定された名前のバイナリーを探します。$ 0に完全なパス名が含まれていない場合、whereis $ scriptnameを実行して結果を変数に保存すると、スクリプトの場所がわかります。


$ 0がファイルへの相対パスを返す可能性があるため、これは機能しません。../perl/test.pl
Lathan

実行可能スクリプトがPATHにない場合はどうなりますか?
Znik 2014年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.