Jak uzyskać pełną ścieżkę do wykonywanego skryptu Perla?

Mam skrypt Perla i muszę określić pełną ścieżkę i nazwę pliku skryptu podczas wykonywania. Odkryłem, że w zależności od tego, jak się nazywa skrypt $0 różni się i czasami zawiera fullpath+filename, a czasami po prostu filename. Ponieważ katalog roboczy również może się różnić, Nie mogę wymyślić sposobu na niezawodne uzyskanie fullpath+filename skryptu.

Ktoś ma rozwiązanie?
Author: serenesat, 2008-09-17

20 answers

$0 to zazwyczaj nazwa Twojego programu, więc co ty na to?

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

Wydaje mi się, że powinno to działać, ponieważ abs_path wie, czy używasz ścieżki względnej czy absolutnej.

Update dla każdego, kto czyta ten rok później, powinieneś przeczytać odpowiedź Drew poniżej. Jest o wiele lepszy niż mój.

 140
Author: Ovid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-22 16:19:21

Jest kilka sposobów:

  • $0 jest aktualnie wykonywanym skryptem dostarczonym przez POSIX, względem bieżącego katalogu roboczego, jeśli skrypt znajduje się na lub poniżej CWD
  • , cwd(), getcwd() i abs_path() są dostarczane przez Cwd moduł i powiedzieć, gdzie skrypt jest uruchamiany z
  • Moduł FindBin zapewnia $Bin & $RealBin zmienne, które zazwyczaj są ścieżką do wykonującego skrypt; moduł ten zapewnia również $Script & $RealScript to jest nazwa skryptu
  • __FILE__ jest rzeczywistym plikiem, z którym interpreter Perla zajmuje się podczas kompilacji, włącznie z jego pełną ścieżką.

Widziałem pierwsze trzy ($0, na Cwd moduł i FindBin module) fail under mod_perl spektakularnie, produkując bezwartościowe wyjście, takie jak '.' lub pusty łańcuch. W takich środowiskach używam __FILE__ i uzyskać ścieżkę z tego za pomocą na File::Basename moduł:

use File::Basename;
my $dirname = dirname(__FILE__);
 213
Author: Drew Stephens,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-12 02:04:00
Use File::Spec;
File::Spec->rel2abs( __FILE__ );

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

 34
Author: Mark,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-19 21:32:17

Myślę, że moduł, którego szukasz to FindBin:

#!/usr/bin/perl
use FindBin;

$0 = "stealth";
print "The actual path to this is: $FindBin::Bin/$FindBin::Script\n";
 16
Author: bmdhacks,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-17 16:22:39

You could use FindBin, Cwd, plik: Basename , lub ich kombinacja. Wszystkie znajdują się w podstawowej dystrybucji Perla IIRC.

Kiedyś używałem Cwd:

Cwd:

use Cwd qw(abs_path);
my $path = abs_path($0);
print "$path\n";
 11
Author: Benjamin W. Smith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-08 07:13:28

Uzyskanie bezwzględnej ścieżki do $0 LUB __FILE__ jest tym, czego chcesz. Jedynym problemem jest to, że jeśli ktoś zrobił {[2] } i $0 był względny -- wtedy musisz uzyskać ścieżkę absolutną w BEGIN{}, Aby zapobiec niespodziankom.

FindBin stara się iść lepiej i płaszczyć się w $PATH za czymś pasującym do basename($0), ale są chwile, kiedy robi to zbyt zaskakujące rzeczy (konkretnie: gdy plik jest "tuż przed Tobą" w cwd.)

File::Fu mA File::Fu->program_name i File::Fu->program_dir za to.

 9
Author: Eric Wilhelm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-19 21:31:20

Jakieś krótkie tło:

Niestety Unix API Nie zapewnia uruchomionego programu z pełną ścieżką do pliku wykonywalnego. W rzeczywistości program wykonujący Twój program może dostarczyć cokolwiek chce w polu, które zwykle mówi twojemu programowi, co to jest. Istnieją, jak wskazują wszystkie odpowiedzi, różne heurystyki do znalezienia prawdopodobnych kandydatów. Ale nic poza przeszukiwaniem całego systemu plików zawsze będzie działać, a nawet to się nie powiedzie, jeśli plik wykonywalny zostanie przeniesiony lub usunięte.

Ale nie chcesz pliku wykonywalnego Perla, który faktycznie działa, ale skrypt, który jest wykonywany. A Perl musi wiedzieć, gdzie jest skrypt, aby go znaleźć. Przechowuje to w __FILE__, podczas gdy {[1] } pochodzi z Unix API. Może to być ścieżka względna, więc przyjmij sugestię Marka i kanonizuj ją za pomocą File::Spec->rel2abs( __FILE__ );

 7
Author: wnoise,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-19 21:30:49

Czy próbowałeś:

$ENV{'SCRIPT_NAME'}

Lub

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

To naprawdę zależy od tego, jak jest wywoływany i czy to CGI, czy jest uruchamiany z normalnej powłoki itp.

 6
Author: Sean,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-17 16:21:33

Aby uzyskać ścieżkę do katalogu zawierającego mój skrypt użyłem kombinacji podanych już odpowiedzi.

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

my $dir = dirname(File::Spec->rel2abs(__FILE__));
 6
Author: Matt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-18 23:12:45

Perlfaq8 odpowiada na bardzo podobne pytanie za pomocą funkcji rel2abs() na $0. Funkcję tę można znaleźć w pliku:: Spec.

 2
Author: moritz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-19 21:31:57

Nie ma potrzeby używania zewnętrznych modułów, wystarczy jedna linia, aby mieć nazwę pliku i ścieżkę względną. Jeśli używasz modułów i musisz zastosować ścieżkę względem katalogu skryptu, ścieżka względna jest wystarczająca.

$0 =~ m/(.+)[\/\\](.+)$/;
print "full path: $1, file name: $2\n";
 2
Author: daniel souza,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-01 16:19:13
#!/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
Author: mkc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-26 14:01:34

Tego szukasz?:

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

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

Wynik będzie wyglądał następująco:

You are running MyFileName.pl now.

Działa zarówno na Windows, jak i Unix.

 1
Author: Yong Li,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-19 21:29:10
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
Author: Yordan Georgiev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-09 13:36:04

Problem z __FILE__ polega na tym, że wyświetli on ścieżkę ".pm "rdzenia, niekoniecznie".uruchomiona ścieżka skryptu cgi "lub". pl". Myślę, że to zależy od tego, jaki jest twój cel.

Wydaje mi się, że Cwd trzeba tylko zaktualizować mod_perl. Oto moja propozycja:

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;

Proszę dodawać wszelkie sugestie.

 0
Author: Jonathan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-14 00:29:25

Bez żadnych zewnętrznych modułów, ważnych dla powłoki, działa dobrze nawet z '../':

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

Test:

$ /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
Author: Putnik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-06 14:39:11

Problem z używaniem dirname(__FILE__) polega na tym, że nie podąża za dowiązaniami symbolicznymi. Musiałem użyć tego, aby mój skrypt podążał za dowiązaniem symbolicznym do rzeczywistej lokalizacji pliku.

use File::Basename;
my $script_dir = undef;
if(-l __FILE__) {
  $script_dir = dirname(readlink(__FILE__));
}
else {
  $script_dir = dirname(__FILE__);
}
 0
Author: DavidG,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-18 07:56:16

Wszystkie rozwiązania wolne od bibliotek nie działają na więcej niż kilka sposobów napisania ścieżki (think ../ lub / bla / x/../ bin// x/../ etc. Moje rozwiązanie wygląda jak poniżej. Mam jeden dziwak: nie mam bladego pojęcia, dlaczego mam dwa razy uruchomić zamienniki. Jeśli nie, dostaję fałszywy"./ "lub"../". Poza tym wydaje mi się dość solidny.

  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
Author: Elmar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-04 10:32:56

Co jest nie tak z $^X ?

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

Da ci pełną ścieżkę do używanego pliku binarnego Perla.

Evert

 -1
Author: user3061015,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-03 11:06:17

Na *nix, prawdopodobnie masz polecenie "whereis", które przeszukuje twoją $PATH szukając pliku binarnego o danej nazwie. Jeśli $0 nie zawiera pełnej nazwy ścieżki, uruchomienie whereis $scriptname i zapisanie wyniku do zmiennej powinno powiedzieć, gdzie znajduje się skrypt.

 -5
Author: foxxtrot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-17 16:18:38