175

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

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

4

23 に答える 23

265

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

  • $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__);
于 2008-09-18T07:30:54.413 に答える
148

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

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

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

更新今年以降に読む人は、Drew's answerを読む必要があります。それは私のものよりもはるかに優れています。

于 2008-09-17T16:19:48.940 に答える
38
use File::Spec;
File::Spec->rel2abs( __FILE__ );

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

于 2008-09-17T16:31:53.327 に答える
16

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

#!/usr/bin/perl
use FindBin;

$0 = "stealth";
print "The actual path to this is: $FindBin::Bin/$FindBin::Script\n";
于 2008-09-17T16:22:39.853 に答える
11

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

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

時計回り:

use Cwd qw(abs_path);
my $path = abs_path($0);
print "$path\n";
于 2008-09-17T16:29:15.110 に答える
9

$0orへの絶対パスを取得する__FILE__ことは、あなたが望むものです。唯一の問題は、誰かが achdir()を実行し、が相対パスだった場合です。驚きを避けるため$0に、絶対パスを取得する必要があります。BEGIN{}

FindBin$PATHは、に一致する何かを求めて で 1 つうまく移動しようとしますがbasename($0)、あまりにも驚くべきことを行う場合があります (具体的には、cwd でファイルが「目の前にある」場合)。

File::FuFile::Fu->program_nameこのFile::Fu->program_dirためです。

于 2008-09-18T07:45:24.393 に答える
7

いくつかの短い背景:

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

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

于 2008-09-17T16:52:24.057 に答える
6

やってみました:

$ENV{'SCRIPT_NAME'}

また

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

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

于 2008-09-17T16:21:33.617 に答える
6

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

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

my $dir = dirname(File::Spec->rel2abs(__FILE__));
于 2013-07-18T23:12:45.777 に答える
2

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

于 2008-09-17T16:34:54.600 に答える
2

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

$0 =~ m/(.+)[\/\\](.+)$/;
print "full path: $1, file name: $2\n";
于 2014-07-01T16:19:13.760 に答える
1

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

use File::Basename;
my $script_dir = undef;
if(-l __FILE__) {
  $script_dir = dirname(readlink(__FILE__));
}
else {
  $script_dir = dirname(__FILE__);
}
于 2014-04-18T07:56:16.510 に答える
1

これをお探しですか?:

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

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

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

You are running MyFileName.pl now.

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

于 2011-04-01T16:27:08.150 に答える
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;

提案があれば追加してください。

于 2013-12-13T11:57:26.893 に答える
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
于 2014-02-06T14:39:11.593 に答える
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 
于 2011-08-09T13:36:04.970 に答える
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/;
于 2014-09-04T10:32:56.000 に答える
0
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]
于 2020-08-23T17:39:37.503 に答える
-5

*nix では、"whereis" コマンドを使用している可能性があります。このコマンドは、$PATH を検索して、指定された名前のバイナリを探します。$0 にフル パス名が含まれていない場合、 whereis $scriptname を実行して結果を変数に保存すると、スクリプトの場所がわかります。

于 2008-09-17T16:18:38.943 に答える