it-swarm-ko.tech

실행중인 Perl 스크립트의 전체 경로는 어떻게 얻습니까?

Perl 스크립트가 있는데 실행 중에 스크립트의 전체 경로와 파일 이름을 결정해야합니다. 스크립트 호출 방식에 따라 $0이 (가) 다양하고 때로는 fullpath+filename 및 때로는 filename이 (가) 포함되어 있음을 발견했습니다. 작업 디렉토리도 다양 할 수 있기 때문에 스크립트의 fullpath+filename을 (를) 안정적으로 얻는 방법을 생각할 수 없습니다.

누구든지 해결책을 얻었습니까?

161
Chris Madden

몇 가지 방법이 있습니다.

  • $0 현재 스크립트가 CWD 이하인 경우 POSIX에서 제공하는 현재 실행중인 스크립트입니다.
  • 또한 cwd(), getcwd()abs_path()Cwd 모듈에서 제공하며 스크립트가 실행되는 위치를 알려줍니다.
  • FindBin 모듈은 _$Bin_ & _$RealBin_ 변수를 제공하여 일반적으로 실행 경로입니다. 스크립트; 이 모듈은 스크립트 이름 인 _$Script_ & _$RealScript_도 제공합니다.
  • __FILE__ 전체 경로를 포함하여 컴파일 중에 Perl 인터프리터가 처리하는 실제 파일입니다.

첫 번째 세 개 ( $0 , Cwd 모듈 및 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

FindBin , Cwd , File :: Basename 또는 이들의 조합을 사용할 수 있습니다. 그들은 모두 Perl IIRC의 기본 배포판에 있습니다.

과거에 Cwd를 사용했습니다.

Cwd :

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

$0 또는 __FILE__의 절대 경로를 얻는 것이 원하는 것입니다. 유일한 문제는 누군가가 chdir()을하고 $0이 상대적인 경우입니다. 놀라움을 막기 위해 BEGIN{}에서 절대 경로를 가져와야합니다.

FindBin은 (는) basename($0)와 (과) 일치하는 무언가를 찾기 위해 $PATH에서 더 나은 곳으로 가려고하지만 시간이 너무 오래 걸리는 경우가 있습니다 (특히 파일이있을 때) cwd에서 "당신 바로 앞에"

File::FuFile::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$0에서 rel2abs() 기능을 사용하여 비슷한 질문에 답변합니다. 이 기능은 File :: Spec에서 찾을 수 있습니다.

2
moritz

외부 모듈을 사용할 필요가 없으며 한 줄만 사용하면 파일 이름과 상대 경로를 가질 수 있습니다. 모듈을 사용 중이고 스크립트 디렉토리에 상대적인 경로를 적용해야하는 경우 상대 경로로 충분합니다.

$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를 사용할 때의 문제점은 모든 심볼릭 링크가 해결 된 상태에서 절대 경로를 반환한다는 것입니다. 제 경우에는 심볼릭 링크가있는 정확한 경로가 필요했습니다. "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
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/../ 등). 내 솔루션은 다음과 같습니다. 한 가지 단점이 있습니다. 왜 교체를 두 번 실행해야하는지에 대한 가장 확실한 아이디어가 없습니다. 그렇지 않은 경우, 의심스러운 "./"또는 "../"를 얻습니다. 나에게 꽤 강해 보인다.

  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