Perlスクリプトがあり、実行中にスクリプトの完全なパスとファイル名を決定する必要があります。スクリプトの呼び出し方法によって$0
が異なり、fullpath+filename
が含まれることがあり、場合によってはfilename
だけが含まれることがあります。作業ディレクトリもさまざまなので、スクリプトのfullpath+filename
を確実に取得する方法は考えられません。
誰にも解決策がありますか?
いくつかの方法があります:
$0
は、POSIXが提供する現在実行中のスクリプトであり、スクリプトがCWD以下である場合は、現在の作業ディレクトリに相対的です。cwd()
、getcwd()
、およびabs_path()
は Cwd
モジュールによって提供され、スクリプトの実行元を示しますFindBin
は、通常が実行スクリプトへのパスである$Bin
および$RealBin
変数を提供します。このモジュールは、スクリプトの名前である$Script
&$RealScript
も提供します__FILE__
は、Perlインタープリターがコンパイル中に処理する実際のファイルであり、その完全パスを含みます。最初の3つ( $0
、 Cwd
モジュール、および FindBin
モジュール)がmod_Perl
の下で失敗し、'.'
などの無意味な出力を生成するのを見てきましたまたは空の文字列。そのような環境では、 __FILE__
を使用し、 File::Basename
モジュールを使用して、そこからパスを取得します。
use File::Basename;
my $dirname = dirname(__FILE__);
通常、$ 0はプログラムの名前ですが、これはどうですか?
use Cwd 'abs_path';
print abs_path($0);
相対パスまたは絶対パスのどちらを使用しているかをabs_pathが認識しているため、これは機能するはずです。
Update今年以降読んでいる人は、 Drew's answer を読んでください。それは私のものよりもはるかに優れています。
Use File::Spec;
File::Spec->rel2abs( __FILE__ );
お探しのモジュールはFindBinだと思います:
#!/usr/bin/Perl
use FindBin;
$0 = "stealth";
print "The actual path to this is: $FindBin::Bin/$FindBin::Script\n";
FindBin 、 Cwd 、 File :: Basename 、またはこれらの組み合わせを使用できます。それらはすべて、Perl IIRCの基本配布物に含まれています。
過去にCwdを使用しました。
Cwd:
use Cwd qw(abs_path);
my $path = abs_path($0);
print "$path\n";
$0
または__FILE__
への絶対パスを取得することが必要です。唯一の問題は、誰かがchdir()
を実行し、$0
が相対的だった場合です-驚きを防ぐために、BEGIN{}
で絶対パスを取得する必要があります。
FindBin
はbasename($0)
に一致するものを探して$PATH
をより良くしようと試みますが、あまりにも驚くべきことを行う場合があります(具体的には、ファイルがcwdの「目の前」
File::Fu
には、File::Fu->program_name
とFile::Fu->program_dir
があります。
短い背景:
残念ながら、Unix APIは実行可能プログラムへの完全なパスを持つ実行中のプログラムを提供しません。実際、あなたのプログラムを実行するプログラムは、通常それが何であるかをあなたのプログラムに伝えるフィールドで何でも提供できます。すべての答えが指摘しているように、有望な候補を見つけるためのさまざまなヒューリスティックがあります。しかし、ファイルシステム全体を検索する以外に常に機能するものはなく、実行可能ファイルが移動または削除された場合でも失敗します。
ただし、実際に実行されているPerl実行可能ファイルは必要ありませんが、実行中のスクリプトは必要です。そして、Perlはスクリプトがそれを見つける場所を知る必要があります。これは__FILE__
に保存されますが、$0
はUnix APIからのものです。これは依然として相対パスである可能性があるため、Markの提案を受けて、File::Spec->rel2abs( __FILE__ );
で正規化します
スクリプトを含むディレクトリへのパスを取得するために、すでに与えられた回答の組み合わせを使用しました。
#!/usr/bin/Perl
use strict;
use warnings;
use File::Spec;
use File::Basename;
my $dir = dirname(File::Spec->rel2abs(__FILE__));
やってみました:
$ENV{'SCRIPT_NAME'}
または
use FindBin '$Bin';
print "The script is located in $Bin.\n";
呼び出される方法と、CGIか通常のシェルから実行されるかなどに大きく依存します。
perlfaq8 は、$0
でrel2abs()
関数を使用して非常によく似た質問に答えます。この関数はFile :: Specにあります。
外部モジュールを使用する必要はありません。ファイル名と相対パスを指定できるのは1行だけです。モジュールを使用していて、スクリプトディレクトリへの相対パスを適用する必要がある場合は、相対パスで十分です。
$0 =~ m/(.+)[\/\\](.+)$/;
print "full path: $1, file name: $2\n";
これを探していますか?:
my $thisfile = $1 if $0 =~
/\\([^\\]*)$|\/([^\/]*)$/;
print "You are running $thisfile
now.\n";
出力は次のようになります。
You are running MyFileName.pl now.
WindowsとUnixの両方で動作します。
#!/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
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
「トップ」の答えはどれも私にとって適切ではありませんでした。 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));
}
dirname(__FILE__)
を使用した場合の問題は、シンボリックリンクをたどらないことです。実際のファイルの場所へのシンボリックリンクをたどるには、スクリプトにこれを使用する必要がありました。
use File::Basename;
my $script_dir = undef;
if(-l __FILE__) {
$script_dir = dirname(readlink(__FILE__));
}
else {
$script_dir = dirname(__FILE__);
}
__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;
提案を追加してください。
シェルに有効な外部モジュールがなくても、「../」でもうまく機能します。
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
ライブラリを使用しないソリューションはすべて、パスを記述するいくつかの方法以外では実際には機能しません(../または/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/;