Perlスクリプトがあり、実行中にスクリプトのフルパスとファイル名を決定する必要があります。スクリプトの呼び出し方法によって$0
異なり、場合によってはとが含まれるfullpath+filename
こともありますfilename
。作業ディレクトリも異なる可能性があるためfullpath+filename
、スクリプトを確実に取得する方法を考えることはできません。
誰かが解決策を手に入れましたか?
いくつかの方法があります:
$0
スクリプトが CWD 以下にある場合、現在の作業ディレクトリに相対的な、POSIX によって提供される現在実行中のスクリプトです。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 は、相対パスまたは絶対パスを使用しているかどうかを認識しているため、これは機能するはずです。
更新今年以降に読む人は、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";
$0
orへの絶対パスを取得する__FILE__
ことは、あなたが望むものです。唯一の問題は、誰かが achdir()
を実行し、が相対パスだった場合です。驚きを避けるため$0
に、絶対パスを取得する必要があります。BEGIN{}
FindBin
$PATH
は、に一致する何かを求めて で 1 つうまく移動しようとしますがbasename($0)
、あまりにも驚くべきことを行う場合があります (具体的には、cwd でファイルが「目の前にある」場合)。
File::Fu
とFile::Fu->program_name
このFile::Fu->program_dir
ためです。
いくつかの短い背景:
残念ながら、Unix API は、実行中のプログラムに実行可能ファイルへのフル パスを提供しません。実際、あなたのプログラムを実行するプログラムは、通常プログラムが何であるかを伝えるフィールドで必要なものを何でも提供できます。すべての回答が指摘しているように、可能性の高い候補を見つけるためのさまざまなヒューリスティックがあります。しかし、ファイルシステム全体を検索すること以外は常に機能し、実行可能ファイルが移動または削除された場合でも失敗します。
しかし、実際に実行されている Perl 実行可能ファイルではなく、実行中のスクリプトが必要です。また、Perl は、スクリプトを見つけるためにスクリプトがどこにあるかを知る必要があります。これは に保存されますが__FILE__
、$0
は Unix API からのものです。これはまだ相対パスである可能性があるため、Markの提案を取り入れて正規化しますFile::Spec->rel2abs( __FILE__ );
やってみました:
$ENV{'SCRIPT_NAME'}
また
use FindBin '$Bin';
print "The script is located in $Bin.\n";
それは、それがどのように呼び出されているか、それが CGI であるか、通常のシェルから実行されているかなどに大きく依存します。
スクリプトを含むディレクトリへのパスを取得するために、既に与えられた回答の組み合わせを使用しました。
#!/usr/bin/perl
use strict;
use warnings;
use File::Spec;
use File::Basename;
my $dir = dirname(File::Spec->rel2abs(__FILE__));
perlfaq8rel2abs()
は、の関数を使用して非常によく似た質問に答えます$0
。その関数はFile::Specにあります。
外部モジュールを使用する必要はありません。1 行だけでファイル名と相対パスを指定できます。モジュールを使用していて、スクリプト ディレクトリからの相対パスを適用する必要がある場合は、相対パスで十分です。
$0 =~ m/(.+)[\/\\](.+)$/;
print "full path: $1, file name: $2\n";
使用するだけの問題dirname(__FILE__)
は、シンボリックリンクをたどらないことです。スクリプトが実際のファイルの場所へのシンボリックリンクをたどるには、これを使用する必要がありました。
use File::Basename;
my $script_dir = undef;
if(-l __FILE__) {
$script_dir = dirname(readlink(__FILE__));
}
else {
$script_dir = dirname(__FILE__);
}
これをお探しですか?:
my $thisfile = $1 if $0 =~
/\\([^\\]*)$|\/([^\/]*)$/;
print "You are running $thisfile
now.\n";
出力は次のようになります。
You are running MyFileName.pl now.
Windows と Unix の両方で動作します。
問題__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
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
すべてのライブラリフリーのソリューションは、パスを記述するいくつかの方法以上では実際には機能しません (../ または /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/;
use File::Basename;
use Cwd 'abs_path';
print dirname(abs_path(__FILE__)) ;
ドリューの答えは私に与えました:
「.」
$ cat >testdirname
use File::Basename;
print dirname(__FILE__);
$ perl testdirname
.$ perl -v
This is perl 5, version 28, subversion 1 (v5.28.1) built for x86_64-linux-gnu-thread-multi][1]
*nix では、"whereis" コマンドを使用している可能性があります。このコマンドは、$PATH を検索して、指定された名前のバイナリを探します。$0 にフル パス名が含まれていない場合、 whereis $scriptname を実行して結果を変数に保存すると、スクリプトの場所がわかります。