Как мне получить полный путь к исполняемому Perl-скрипту? - PullRequest
159 голосов
/ 17 сентября 2008

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

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

Ответы [ 21 ]

2 голосов
/ 01 июля 2014

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

$0 =~ m/(.+)[\/\\](.+)$/;
print "full path: $1, file name: $2\n";
1 голос
/ 01 апреля 2011

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

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

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

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

You are running MyFileName.pl now.

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

1 голос
/ 26 ноября 2012
#!/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

0 голосов
/ 18 апреля 2014

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

use File::Basename;
my $script_dir = undef;
if(-l __FILE__) {
  $script_dir = dirname(readlink(__FILE__));
}
else {
  $script_dir = dirname(__FILE__);
}
0 голосов
/ 06 февраля 2014

Без каких-либо внешних модулей, допустимых для оболочки, хорошо работает даже с '../':

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 голосов
/ 13 декабря 2013

Проблема с __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;

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

0 голосов
/ 03 декабря 2013

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

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

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

Эверт

0 голосов
/ 04 сентября 2014

Все безбиблиотечные решения на самом деле не работают для нескольких путей написания пути (подумайте ../ или /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 голосов
/ 09 августа 2011
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 голосов
/ 23 октября 2018

Ни один из "лучших" ответов не был для меня правильным. Проблема с использованием FindBin '$ Bin' или Cwd заключается в том, что они возвращают абсолютный путь со всеми разрешенными символическими ссылками. В моем случае мне нужен был точный путь с символическими ссылками - так же, как возвращает Unix команду "pwd", а не "pwd -P". Следующая функция обеспечивает решение:

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));
}
...