Как получить полный путь к скрипту Perl, который выполняется?


у меня есть скрипт на Perl, и нужно определить полный путь и имя файла скрипта во время выполнения. Я обнаружил, что в зависимости от того, как вы вызываете скрипт меняется и иногда содержит fullpath+filename а иногда просто filename. Потому что рабочий каталог может меняться, а я не могу придумать способ надежно получить fullpath+filename скрипта.

у кого-нибудь есть решение?

20 150

20 ответов:

$0-это обычно Название вашей программы, так как насчет этого?

use Cwd 'abs_path';
print abs_path();

Мне кажется, что это должно работать как abs_path знает, если вы используете относительный или абсолютный путь.

обновление для тех, кто читает это годы спустя, вы должны прочитать ответ Дрю ниже. Это намного лучше, чем у меня.

есть несколько способов:

  • является ли текущий выполняемый скрипт, предоставленный POSIX, относительно текущего рабочего каталога, если скрипт находится на уровне или ниже CWD
  • кроме того, cwd(),getcwd() и abs_path() предусмотрены Cwd модуль и сказать вам, где скрипт запускается из
  • модуль FindBin предоставляет $Bin & $RealBin переменные, которые обычно - это путь к исполняемому скрипту; этот модуль также предоставляет $Script & $RealScript имя скрипта
  • __FILE__ - это фактический файл, который интерпретатор Perl обрабатывает во время компиляции, включая его полный путь.

Я видел первые три ( на Cwd и FindBin модуль) проваливаются под mod_perl эффектно, производство бесполезной продукции, такой как '.' или пустая строка. В таких условиях, я использую __FILE__ и получить путь от этого с помощью File::Basename модуль:

use File::Basename;
my $dirname = dirname(__FILE__);
Use File::Spec;
File::Spec->rel2abs( __FILE__ );

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

Я думаю, что модуль, который вы ищете, это FindBin:

#!/usr/bin/perl
use FindBin;

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

вы могли бы использовать FindBin, Cwd,File:: Basename, или их сочетание. Все они находятся в базовом распределении Perl IIRC.

Я использовал Cwd в прошлом:

Cwd:

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

получение абсолютного пути к или __FILE__ это то, что вы хотите. Единственная проблема-если кто-то сделал chdir() и был относительным, тогда вам нужно получить абсолютный путь в BEGIN{} чтобы предотвратить любые сюрпризы.

FindBin пытается идти один лучше и пресмыкаться в $PATH для чего-то, соответствующего basename(), но бывают случаи, когда это делает слишком удивительные вещи (в частности: когда файл находится "прямо перед вами" в cwd.)

File::Fu и File::Fu->program_name и File::Fu->program_dir для этого.

несколько коротких справочная информация:

к сожалению, UNIX API не предоставляет запущенную программу с полным путем к исполняемому файлу. Фактически, программа, выполняющая вашу, может предоставить все, что она хочет в поле, которое обычно говорит вашей программе, что это такое. Существуют, как указывают все ответы, различные эвристики для поиска вероятных кандидатов. Но ничего, кроме поиска всей файловой системы, всегда будет работать, и даже это не удастся, если исполняемый файл будет перемещен или удаленный.

но вы не хотите исполняемый файл Perl, который на самом деле работает, но скрипт, который он выполняет. И Perl должен знать, где находится скрипт, чтобы найти его. Он хранит это в __FILE__, а из UNIX API. Это все еще может быть относительный путь, поэтому примите предложение Марка и канонизируйте его с помощью 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__));

perlfaq8 ответ на очень похожий вопрос с помощью на . Эту функцию можно найти в файле::Spec.

нет необходимости использовать внешние модули, только с одной строкой вы можете иметь имя файла и относительный путь. Если вы используете модули и вам нужно применить путь относительно каталога скрипта, относительного пути достаточно.

 =~ m/(.+)[\/\](.+)$/;
print "full path: , file name: \n";
#!/usr/bin/perl -w
use strict;


my $path = ;
$path =~ s/\.\///g;
if ($path =~ /\//){
  if ($path =~ /^\//){
    $path =~ /^((\/[^\/]+){1,}\/)[^\/]+$/;
    $path = ;
    }
  else {
    $path =~ /^(([^\/]+\/){1,})[^\/]+$/;
    my $path_b = ;
    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

вы ищете это?:

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

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

вывод будет выглядеть так:

You are running MyFileName.pl now.

Он работает как на Windows, так и на Unix.

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() ; 
        #debug print "$ScriptAbsolutPath is $ScriptAbsolutPath \n" ;
        $ScriptAbsolutPath =~ m/^(.*)(\|\/)(.*)\.([a-z]*)/; 
        $RunDir =  ; 
        #debug print "$1 is  \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 

проблема с __FILE__ это то, что он будет печатать основной модуль ".pm" путь не обязательно ".CGI" или". pl " путь сценария, который выполняется. Я думаю, это зависит от того, какова ваша цель.

мне кажется, что 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 .='/'. if  =~/([^\/]*)$/; #keep the filename only
print "self=$self\n";

проблема только с использованием dirname(__FILE__) это то, что он не следует символическим ссылкам. Я должен был использовать это для моего скрипта, чтобы следовать символической ссылке на фактическое местоположение файла.

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

все решения без библиотек на самом деле не работают более чем на несколько способов написания пути (подумайте ../ или / бла / х/../закром.//икс././ прием. Мое решение выглядит следующим образом. У меня есть одна причуда: я не имею ни малейшего представления, почему я должен запускать замены дважды. Если я этого не сделаю, я получу поддельный "./" или." ./". Кроме того, он кажется мне довольно прочным.

  my $callpath = ;
  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/(.*)\/([^\/]+)//;

что с $^X ?

#!/usr/bin/env perl<br>
print "This is executed by $^X\n";

даст вам полный путь к исполняемому файлу Perl используется.

Эверт

на *nix у вас, вероятно, есть команда "whereis", которая ищет ваш $PATH, ищущий двоичный файл с заданным именем. Если $0 не содержит полного имени пути, запуск whereis $scriptname и сохранение результата в переменную должны сообщить вам, где находится скрипт.