it-swarm-tr.com

Yürütülmekte olan bir Perl betiğinin tam yolunu nasıl bulabilirim?

Perl betiği var ve yürütme sırasında betiğin tam yolunu ve dosya adını belirlemeliyim. $0 betiğini nasıl çağırdığınıza bağlı olarak değişebilir ve bazen fullpath+filename ve bazen sadece filename içerir. Çalışma dizini değişkenlik gösterebileceği için betiğin fullpath+filename'sunu güvenilir bir şekilde almanın bir yolunu düşünemiyorum.

Bir çözümü olan var mı?

156
Chris Madden

Birkaç yol var:

  • $0 , eğer komut dosyası CWD'de veya altındaysa, geçerli çalışma dizinine göre POSIX tarafından sağlanan halihazırda çalışan komut dosyasıdır.
  • Ek olarak, cwd(), getcwd() ve abs_path(), Cwd / modülü tarafından sağlanır ve komut dosyasının nerden çalıştırıldığını size söyler.
  • FindBin / modülü,// ​​[[] kodunun genellikle yürüten komut dosyasının yolu olduğu $Bin & $RealBin değişkenlerini sağlar; Bu modül ayrıca betiğin adı olan $Script & $RealScript işlevini de sağlar.
  • __FILE__ /, Perl yorumlayıcısının, derleme sırasındaki tam yolu dahil olmak üzere ele aldığı asıl dosyadır.

İlk üç ( $0 /, Cwd / modülü ve FindBin modülü), mod_Perl öğesinin altında başarısız oldu, '.' veya boş bir dize gibi değersiz çıktılar ürettim. Bu tür ortamlarda, __FILE__ / kullanıyorum ve File::Basename modülünü kullanarak yolunu buluyorum:

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

$ 0 tipik olarak programınızın adıdır, peki buna ne dersiniz?

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

Bana göre bu göreceli veya mutlak bir yol kullanıyorsanız abs_path'ın bildiği gibi çalışmalı.

Güncelleme Bu yıllar sonra okuyanlar için, Drew'un cevabını aşağıda okumalısınız. Benimkinden çok daha iyi.

143
Ovid
Use File::Spec;
File::Spec->rel2abs( __FILE__ );

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

34
Mark

Sanırım aradığınız modül FindBin:

#!/usr/bin/Perl
use FindBin;

$0 = "stealth";
print "The actual path to this is: $FindBin::Bin/$FindBin::Script\n";
16
bmdhacks

FindBin , Cwd , Dosya :: Basename veya bunların bir birleşimini kullanabilirsiniz. Hepsi Perl IIRC'nin temel dağılımındalar.

Geçmişte Cwd kullandım:

Cwd:

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

$0 veya __FILE__ 'a giden mutlak yolu almak istediğiniz şeydir. Tek sorun, eğer birisi chdir() yaptıysa ve $0 göreceli ise - herhangi bir sürpriz yapmamak için BEGIN{} içinde mutlak yolu bulmanız gerekir.

FindBin, basename($0) ile eşleşen bir şey için $PATH içinde bir tanesine daha iyi gitmeye çalışır. Ancak, bunun çok şaşırtıcı olan şeyleri yaptığı zamanlar vardır (özellikle: dosya cwd'de "tam önünde" olduğunda)

File::Fu, bunun için File::Fu->program_name ve File::Fu->program_dir değerlerine sahiptir.

9
Eric Wilhelm

Bazı kısa arka plan:

Maalesef Unix API, çalıştırılabilir programın tam yolu ile çalışan bir program sağlamıyor. Aslında, sizinkini çalıştıran program, normalde programınıza ne olduğunu söyleyen alanda ne isterse sağlayabilir. Tüm cevapların işaret ettiği gibi, olası adayları bulmak için çeşitli buluşsal yöntemler vardır. Ancak, tüm dosya sisteminde arama yapmaktan hiç kaçınan bir şey her zaman işe yaramaz ve çalıştırılabilir taşınır veya kaldırılırsa bu bile başarısız olur.

Fakat Perl'in çalıştırılabilir olmasını istemiyorsunuz, yani gerçekte çalışan nedir, ancak çalıştırmakta olduğu komut dosyası. Ve Perl'in senaryoyu nerede bulacağını bilmesi gerekiyor. Bunu __FILE__ içinde saklar, $0 ise Unix API'sındandır. Bu hala göreceli bir yol olabilir, bu yüzden Mark'ın önerisini al ve File::Spec->rel2abs( __FILE__ ); ile kanonize et

7
wnoise

Komut dosyamı içeren dizine ulaşmak için daha önce verilen cevapların bir kombinasyonunu kullandım.

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

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

Denedin mi:

$ENV{'SCRIPT_NAME'}

veya

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

Gerçekten nasıl çağrıldığına ve CGI veya normal bir Shell'den çalıştırılmamasına bağlı.

6
Sean

perlfaq8 , $0 üzerindeki rel2abs() işlevini kullanarak çok benzer bir soruyu yanıtlar. Bu işlev Dosya :: Spec.

2
moritz

Harici modülleri kullanmaya gerek yoktur, sadece bir satırda dosya adına ve göreceli yola sahip olabilirsiniz. Modüller kullanıyorsanız ve script dizinine göre bir yol uygulamanız gerekiyorsa, göreceli yol yeterlidir.

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

Bunu mu arıyorsunuz?

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

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

Çıktı şöyle görünecek:

You are running MyFileName.pl now.

Hem Windows hem de Unix'te çalışır.

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

"En iyi" cevapların hiçbiri benim için doğru değildi. FindBin '$ Bin' veya Cwd kullanmanın problemi, tüm sembolik linkler çözülmüş olarak mutlak bir yol döndürmeleridir. Benim durumumda sembolik bağları olan tam yola ihtiyacım vardı - Unix komutunu "pwd" ve "pwd -P" değil. Aşağıdaki işlev çözümü sunar:

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

Sadece dirname(__FILE__) işlevini kullanmanın sorunu, sembolik bağlantıları izlememesidir. Bunu komut dosyamın asıl dosya konumuna giden link bağlantısını izlemek için kullanmak zorunda kaldım.

use File::Basename;
my $script_dir = undef;
if(-l __FILE__) {
  $script_dir = dirname(readlink(__FILE__));
}
else {
  $script_dir = dirname(__FILE__);
}
0
DavidG

__FILE__ ile ilgili sorun, çalışan ".cgi" veya ".pl" komut dosyası yolunu değil, ".pm" çekirdek modülünü yazmasıdır. Sanırım amacın ne olduğuna bağlı.

Bana öyle geliyor ki Cwd / mod_Perl için güncellenmesi gerekiyor. İşte benim önerim:

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;

Lütfen önerilerinizi ekleyin.

0
Jonathan

Herhangi bir harici modül olmadan, Shell için geçerlidir, '../' ile bile iyi çalışır:

my $self = `pwd`;
chomp $self;
$self .='/'.$1 if $0 =~/([^\/]*)$/; #keep the filename only
print "self=$self\n";

Ölçek:

$ /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

Kütüphane içermeyen tüm çözümler aslında bir yol yazmanın birkaç yolundan daha fazla işe yaramaz (düşünün ../veya /bla/x/../bin/./x/../ vb.) Bir tutam var: Değişimleri neden iki kez yapmam gerektiğine dair en ufak bir fikrim yok. Yapmazsam, sahte bir "./" veya "../" alırım. Bunun dışında bana oldukça sağlam görünüyor.

  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