Wie bekomme ich den vollständigen Pfad zu einem Perl-Skript, das ausgeführt wird?



10 Answers

Es gibt ein paar Möglichkeiten:

  • $0 ist das derzeit von POSIX ausgeführte Skript relativ zum aktuellen Arbeitsverzeichnis, wenn das Skript auf oder unter dem CWD liegt
  • Außerdem werden cwd() , getcwd() und abs_path() vom Cwd Modul zur Verfügung gestellt und sagen Ihnen, wo das Skript ausgeführt wird
  • Das Modul FindBin stellt die Variablen $Bin & $RealBin , die normalerweise der Pfad zum ausführenden Skript sind; Dieses Modul stellt auch $Script & $RealScript , die den Namen des Skripts darstellen
  • __FILE__ ist die eigentliche Datei, mit der der Perl-Interpreter während der Kompilierung arbeitet, einschließlich des vollständigen Pfads.

Ich habe gesehen, wie die ersten drei ( $0 , das Cwd Modul und das FindBin Modul) spektakulär unter mod_perl versagten und wertlose Ausgaben wie '.' oder eine leere Zeichenfolge. In solchen Umgebungen verwende ich __FILE__ und erhalte den Pfad von diesem mit dem Modul File::Basename :

use File::Basename;
my $dirname = dirname(__FILE__);
Question

Ich habe Perl-Skript und muss den vollständigen Pfad und Dateinamen des Skripts während der Ausführung ermitteln. Ich entdeckte, dass je nachdem, wie Sie das Skript aufrufen $0 variiert und manchmal den fullpath+filename und manchmal nur filename . Da das Arbeitsverzeichnis auch variieren kann, kann ich mir keinen Weg fullpath+filename , wie der fullpath+filename des Skripts zuverlässig fullpath+filename .

Jeder hat eine Lösung?




Ich denke, das Modul, das Sie suchen, ist FindBin:

#!/usr/bin/perl
use FindBin;

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



Den absoluten Pfad zu $0 oder __FILE__ ist was Sie wollen. Das einzige Problem ist, wenn jemand ein chdir() und die $0 relativ war - dann müssen Sie den absoluten Pfad in einem BEGIN{} , um Überraschungen zu vermeiden.

FindBin versucht, einen besseren Weg zu finden und im $PATH nach etwas zu suchen, das dem basename($0) , aber es gibt Zeiten, in denen das viel zu überraschende Dinge tut (genauer gesagt: wenn die Datei "direkt vor dir" ist) der cwd.)

File::Fu hat dafür File::Fu->program_name und File::Fu->program_dir .




Einige kurze Hintergründe:

Leider bietet die Unix-API kein laufendes Programm mit dem vollständigen Pfad zur ausführbaren Datei. Tatsächlich kann das Programm, das Sie ausführen, in dem Feld, was Ihrem Programm normalerweise sagt, was es ist, alles bereitstellen, was es will. Es gibt, wie alle Antworten zeigen, verschiedene Heuristiken, um wahrscheinliche Kandidaten zu finden. Aber nichts weniger als das Durchsuchen des gesamten Dateisystems wird immer funktionieren, und selbst das wird fehlschlagen, wenn die ausführbare Datei verschoben oder entfernt wird.

Aber Sie wollen nicht die Perl-Programmdatei, die gerade ausgeführt wird, sondern das Skript, das sie ausführt. Und Perl muss wissen, wo das Skript es finden soll. Es speichert dies in __FILE__ , während $0 von der Unix-API stammt. Dies kann immer noch ein relativer Pfad sein, also nehmen Sie Marks Vorschlag und kanonisieren Sie ihn mit File::Spec->rel2abs( __FILE__ );




perlfaq8 beantwortet eine sehr ähnliche Frage mit der Funktion rel2abs() auf $0 . Diese Funktion kann in File :: Spec gefunden werden.




#!/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




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 



Ohne externe Module, gültig für Shell, funktioniert auch mit '../' gut:

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

Prüfung:

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



Alle Bibliotheken-freien Lösungen arbeiten nicht wirklich für mehr als ein paar Wege, um einen Pfad zu schreiben (denken ../ oder /bla/x/../bin/./x/../ usw. Meine Lösung sieht wie aus Ich habe eine Eigenart: Ich habe nicht die leiseste Ahnung, warum ich den Ersatz zweimal ausführen muss. Wenn ich das nicht tue, bekomme ich ein falsches "./" oder "../". Abgesehen davon, es scheint mir ziemlich robust.

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



Auf * nix haben Sie wahrscheinlich den Befehl "whereis", der Ihren $ PATH nach einer Binärdatei mit einem bestimmten Namen sucht. Wenn $ 0 nicht den vollständigen Pfadnamen enthält, sollte die Ausführung von whereis $ scriptname und das Speichern des Ergebnisses in eine Variable Ihnen sagen, wo sich das Skript befindet.




Related