실행중인 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 인터프리터가 처리하는 실제 파일입니다.

첫 번째 세 개 ( $0, Cwd모듈 및 FindBin모듈)가 놀랍게 실패 하여 빈 문자열 mod_perl과 같은 가치없는 출력을 생성하는 것을 보았습니다 '.'. 그러한 환경에서는 모듈 __FILE__을 사용하여 경로를 사용하고 경로를 얻습니다 File::Basename.

use File::Basename;
my $dirname = dirname(__FILE__);


8
경로와 함께 이름 만 포함 할 수 있으므로 abs_path를 _____FILE_____에 사용해야합니다.
여진

6
@vicTROLLA 아마도이 대답의 가장 큰 권장 사항 (dirname과 함께 사용 __FILE__)이 예상대로 작동하지 않습니까? 스크립트가 실행 된 상대 경로로 끝나고 허용 된 답변은 전체 경로를 제공합니다.
이즈 카타

10
dirname(__FILE__)당신이 확인해야 설치 위치에 다른 파일의 위치를 찾으려는 실행 파일과 장소를 연결 그렇다면, 심볼릭 링크를 따르지 않는 if( -l __FILE__)다음과 dirname(readlink(__FILE__)).
DavidG

3
@IliaRostovtsev이 incantation으로 모듈이 표준 모듈에 처음 포함 된시기를 찾을 수 있습니다 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 's answer를 읽어야 합니다. 내 것보다 훨씬 낫다.


11
Windows $ 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
leonbloy

2
@leonbloy 스크립트 인라인 (with -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

당신은 사용할 수 FindBin , CWD , 파일 : 기본 이름 또는 이들의 조합. 그들은 모두 Perl IIRC의 기본 배포판에 있습니다.

나는 과거에 Cwd를 사용했다.

Cwd :

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

@bmdhacks, 맞습니다. 추정은 0 $을 변경하지 않았다는 것입니다. 예를 들어, 스크립트가 시작되는 즉시 (초기화 블록에서) 또는 $ 0을 변경하지 않는 다른 곳에서 위의 작업을 수행합니다. 그러나 $ 0는 'ps'유닉스 도구에서 볼 수있는 프로세스 설명을 변경하는 훌륭한 방법입니다. :) 현재 프로세스 상태 등을 표시 할 수 있습니다. 이는 프로그래머 목적에 따라
다릅니다.

9

$0또는 __FILE__원하는 경로를 얻는 것입니다. 누군가를 한 경우에만 문제는 chdir()하고는 $0당신이에 절대 경로를 얻을 필요가 - 친척 BEGIN{}어떤 놀라움을 방지 할 수 있습니다.

FindBin에서 $PATH일치하는 무언가를 위해 더 잘되고 그루브를 시도 basename($0)하지만, 너무 놀라운 일을하는 경우가 있습니다 (특히 : 파일이 cwd에서 "바로 앞에 있음").

File::FuFile::Fu->program_nameFile::Fu->program_dir이에 대한.


chdir()컴파일 타임에 누군가가 (영구적으로) 어리석은 것일 가능성이 있습니까?
SamB

스크립트가 시작될 때 현재 디렉토리와 $ 0을 기반으로 모든 작업을 수행하십시오.
Znik

7

일부 짧은 배경 :

불행히도 Unix API는 실행 파일에 대한 전체 경로를 가진 실행중인 프로그램을 제공하지 않습니다. 실제로, 당신을 실행하는 프로그램은 일반적으로 프로그램이 무엇인지 알려주는 필드에서 원하는 것을 제공 할 수 있습니다. 모든 답변에서 알 수 있듯이, 가능한 후보를 찾기위한 다양한 휴리스틱이 있습니다. 그러나 전체 파일 시스템을 검색하는 데 항상 부족한 것은 없으며 실행 파일을 이동하거나 제거해도 실패합니다.

그러나 실제로 실행중인 Perl 실행 파일은 원하지 않지만 실행중인 스크립트는 원하지 않습니다. 그리고 Perl은 스크립트가 어디에 있는지 알아야합니다. 유닉스 API에서 온 __FILE__동안 이것을에 저장합니다 $0. 이것은 여전히 ​​상대 경로 일 수 있으므로 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와 완전히 호환되지 않으며 다른 바이너리에서 직접 스크립트를 호출 할 때 호환되지 않습니다. 이 보증 대상이 설정되어 있다는 보증은 없습니다. 위의 방법은 훨씬 더 유용합니다.
Znik

6

내 스크립트가 들어있는 디렉토리의 경로를 얻으려면 이미 주어진 답변의 조합을 사용했습니다.

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

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

2

perlfaq8rel2abs()on 함수를 사용하여 매우 비슷한 질문에 답변합니다 $0. 이 기능은 File :: Spec에서 찾을 수 있습니다.


2

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

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

"."만 표시하므로 "./myscript.pl"과 같이 실행하면 스크립트의 올바른 전체 경로를 제공하지 않습니다. 대신에. 그러나 나는 여전히이 솔루션을 좋아합니다.
Keve

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
코드만으로 대답하지 마십시오. 이것이 왜 정답인지 설명하십시오.
이 테일러

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__는 코어 모듈 ".pm"경로가 반드시 실행중인 ".cgi"또는 ".pl"스크립트 경로 일 필요는 없다는 것입니다. 나는 그것이 당신의 목표가 무엇인지에 달려 있다고 생각합니다.

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/../ 등). 내 솔루션은 다음과 같습니다. 한 가지 단점이 있습니다. 왜 교체를 두 번 실행해야하는지에 대한 가장 확실한 아이디어가 없습니다. 그렇지 않은 경우, 의심스러운 "./"또는 "../"를 얻습니다. 나에게 꽤 강해 보인다.

  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
그것은 필요한 스크립트에 대한 경로와 펄 바이너리에 대한 경로를 제공합니다
Putnik

-5

* nix에는 "whereis"명령이있을 수 있습니다.이 명령은 $ PATH에서 지정된 이름의 이진 파일을 찾습니다. $ 0에 전체 경로 이름이 없으면 whereis $ scriptname을 실행하고 결과를 변수에 저장하면 스크립트의 위치를 ​​알려줍니다.


$ 0도 파일에 대한 상대 경로를 반환 할 수 있으므로 작동하지 않습니다. ../perl/test.pl
Lathan

실행 스크립트가 PATH를 벗어나면 어떻게됩니까?
Znik
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.