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

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

Кто-нибудь получил решение?

вопрос задан 17.09.2008
Chris Madden
928 репутация

20 ответов


  • 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 
    
    ответ дан Yordan Georgiev, с репутацией 2420, 9.08.2011
  • 0 рейтинг

    Некоторый короткий фон:

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

    Но вам не нужен исполняемый файл Perl, который фактически выполняется, а сценарий, который он выполняет. И Perl должен знать, где находится скрипт, чтобы его найти. Он хранит это в __FILE__, в то время как $0 из Unix API. Это все еще может быть относительный путь, поэтому примите предложение Марка и канонизируйте его с File::Spec->rel2abs( __FILE__ );

    ответ дан wnoise, с репутацией 8539, 17.09.2008
  • 0 рейтинг

    Вы можете использовать FindBin , Cwd , File :: Basename или их комбинацию. Они все в базовом дистрибутиве Perl IIRC.

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

    Cwd:

    use Cwd qw(abs_path);
    my $path = abs_path($0);
    print "$path\n";
    
    ответ дан Benjamin W. Smith, с репутацией 492, 17.09.2008
  • 0 рейтинг
    Use File::Spec;
    File::Spec->rel2abs( __FILE__ );
    

    http: // perldoc. Perl. орг / Файл / Spec / Unix. HTML

    ответ дан Mark, с репутацией 87068, 17.09.2008
  • 0 рейтинг

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

    use File::Basename;
    my $script_dir = undef;
    if(-l __FILE__) {
      $script_dir = dirname(readlink(__FILE__));
    }
    else {
      $script_dir = dirname(__FILE__);
    }
    
    ответ дан DavidG, с репутацией 2241, 18.04.2014
  • 0 рейтинг

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

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

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

    use File::Basename;
    my $dirname = dirname(__FILE__);
    
    ответ дан Drew Stephens, с репутацией 8681, 18.09.2008
  • 0 рейтинг

    perlfaq8 отвечает на очень похожий вопрос с использованием функции rel2abs() на $0. Эту функцию можно найти в File :: Spec.

    ответ дан moritz, с репутацией 10079, 17.09.2008
  • 0 рейтинг

    Что не так с $^X?

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

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

    Evert

    ответ дан user3061015, с репутацией 11, 3.12.2013
  • 0 рейтинг

    Чтобы получить путь к каталогу, содержащему мой сценарий, я использовал уже приведенную комбинацию ответов.

    #!/usr/bin/perl
    use strict;
    use warnings;
    use File::Spec;
    use File::Basename;
    
    my $dir = dirname(File::Spec->rel2abs(__FILE__));
    
    ответ дан Matt, с репутацией 61, 18.07.2013
  • 0 рейтинг

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

    my $thisfile = $1 if $0 =~
    /\\([^\\]*)$|\/([^\/]*)$/;
    
    print "You are running $thisfile
    now.\n";
    

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

    You are running MyFileName.pl now.
    

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

    ответ дан Yong Li, с репутацией 11, 1.04.2011
  • 0 рейтинг

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

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

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

    ответ дан Eric Wilhelm, с репутацией 473, 18.09.2008
  • 0 рейтинг

    Проблема с __FILE__ в том, что он напечатает основной модуль ". вечера "путь не обязательно". 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;
    

    Пожалуйста, добавьте любые предложения.

    ответ дан Jonathan, с репутацией 381, 13.12.2013
  • 0 рейтинг
    #!/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

    ответ дан mkc, с репутацией 11, 26.11.2012
  • 0 рейтинг

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

    ответ дан foxxtrot, с репутацией 9375, 17.09.2008
  • 0 рейтинг

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

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

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

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

    ответ дан Ovid, с репутацией 8931, 17.09.2008
  • 0 рейтинг

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

    $0 =~ m/(.+)[\/\\](.+)$/;
    print "full path: $1, file name: $2\n";
    
    ответ дан daniel souza, с репутацией 169, 1.07.2014
  • 0 рейтинг

    Вы пробовали:

    $ENV{'SCRIPT_NAME'}
    

    или

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

    Это действительно зависит от того, как он вызывается и является ли он CGI или запускается из обычной оболочки и т. Д.

    ответ дан Sean, с репутацией 3900, 17.09.2008
  • 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
    
    ответ дан Putnik, с репутацией 1256, 6.02.2014
  • 0 рейтинг

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

      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/;
    
    ответ дан Elmar, с репутацией 1, 4.09.2014
  • 0 рейтинг

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

    #!/usr/bin/perl
    use FindBin;
    
    $0 = "stealth";
    print "The actual path to this is: $FindBin::Bin/$FindBin::Script\n";
    
    ответ дан bmdhacks, с репутацией 13134, 17.09.2008