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

StackOverflow https://stackoverflow.com/questions/84932

  •  01-07-2019
  •  | 
  •  

Frage

Ich habe Perl-Skript und muß den vollständigen Pfad und Dateinamen des Skripts während der Ausführung zu bestimmen. Ich entdeckte, dass je nachdem, wie Sie rufen das Skript $0 variiert und manchmal die fullpath+filename enthält und manchmal nur filename. Da das Arbeitsverzeichnis als auch variieren kann ich kann nicht einen Weg finden, um zuverlässig den fullpath+filename des Skripts zu bekommen.

Wer hat eine Lösung?

War es hilfreich?

Lösung

Es gibt ein paar Möglichkeiten:

  • $0 ist die aktuell ausgeführten Skripts wie POSIX, bezogen auf den aktuellen Arbeits vorgesehen Verzeichnis, wenn das Skript auf oder unter dem CWD
  • Zusätzlich cwd(), getcwd() und abs_path() werden von der Cwd Modul und Ihnen sagen, wo die Skript wird ausgeführt von
  • Das Modul FindBin stellt die $Bin & $RealBin Variablen, die in der Regel zum Ausführen von Skripts ist der Pfad; Dieses Modul bietet auch $Script & $RealScript, dass der Name des Skripts
  • sind
  • __FILE__ ist die eigentliche Datei, die Perl-Interpreter behandelt während der Kompilierung, einschließlich der vollständigen Pfad.

Ich habe die ersten drei ( $0 , die Cwd Modul und die FindBin Modul) nicht unter mod_perl spektakulär, wertlos Ausgang wie '.' oder eine leere Zeichenfolge zu erzeugen. In solchen Umgebungen Ich benutze __FILE__ und den Weg bekommen aus, dass die Verwendung der File::Basename Modul:

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

Andere Tipps

$ 0 ist in der Regel der Name des Programms, so wie über das?

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

Es scheint mir, dass dies funktionieren soll als abs_path weiß, wenn Sie einen relativen oder absoluten Pfad verwenden.

Aktualisieren Für alle, noch in diesem Jahr lesen, sollten Sie Drews Antwort unten lesen. Es ist viel besser als meine.

Use File::Spec;
File::Spec->rel2abs( __FILE__ );

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

Ich denke, dass das Modul Sie suchen FindBin ist:

#!/usr/bin/perl
use FindBin;

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

könnten Sie verwenden FindBin Cwd , File :: Basename oder eine Kombination von ihnen. Sie sind alle in der Basisdistribution von Perl IIRC.

Ich habe Cwd in der Vergangenheit:

Cwd:

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

Ankommen der absolute Pfad zum $0 oder __FILE__ ist das, was Sie wollen. Das einzige Problem ist, wenn jemand eine chdir() tat und die $0 war relativ -. Dann müssen Sie den absoluten Pfad in einem BEGIN{} erhalten keine Überraschungen zu verhindern

FindBin versucht man besser und winseln um im $PATH für etwas zu gehen, um die basename($0) passend, aber es gibt Zeiten, in denen das tut weit allzu überraschende Dinge (genauer gesagt: wenn die Datei „rechts vor Ihnen“ in der cwd.)

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

Einige kurze Hintergrund:

Leider ist der Unix-API nicht ein laufendes Programm mit dem vollständigen Pfad zu der ausführbaren Datei zur Verfügung stellen. In der Tat kann das Programm ausgeführt wird Ihnen bieten, was es auf dem Gebiet will, das normalerweise Ihr Programm sagt, was es ist. Es gibt, wie alle Antworten darauf hin, verschiedene Heuristiken für wahrscheinliche Kandidaten zu finden. Aber nichts weniger als das gesamte Dateisystem gesucht wird immer funktionieren, und auch das wird scheitern, wenn die Programmdatei verschoben oder entfernt wird.

Aber Sie wollen nicht die ausführbare Datei Perl, das ist das, was tatsächlich läuft, aber das Skript es ausgeführt wird. Und Perl muss wissen, wo das Skript zu finden ist. Er speichert diese in __FILE__, während $0 aus dem Unix-API ist. Dies kann immer noch ein relativer Pfad sein, so nimmt Marks Vorschlag und canonize es mit File::Spec->rel2abs( __FILE__ );

Haben Sie versucht:

$ENV{'SCRIPT_NAME'}

oder

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

Es hängt wirklich davon ab, wie es genannt wird, und wenn es CGI oder von einem normalen Shell ausgeführt werden, etc.

Um den Pfad zu dem Verzeichnis, in meinem Skript zu bekommen habe ich eine Kombination von Antworten schon gegeben.

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

my $dir = dirname(File::Spec->rel2abs(__FILE__));

perlfaq8 beantwortet eine sehr ähnliche Frage mit der rel2abs() Funktion auf $0 verwenden. Diese Funktion kann in Datei zu finden :: Spec.

Es gibt keine Notwendigkeit, externe Module zu verwenden, mit nur einer Zeile, die Sie die Dateinamen und relativen Pfad haben. Wenn Sie Module verwenden und benötigen einen Pfad relativ zum Skriptverzeichnis anwenden, der relative Pfad ist genug.

$0 =~ m/(.+)[\/\\](.+)$/;
print "full path: $1, file name: $2\n";
#!/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

Suchen Sie diese:

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

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

Die Ausgabe wird wie folgt aussehen:

You are running MyFileName.pl now.

Es funktioniert auf Windows und 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($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 

Das Problem mit __FILE__ ist, dass es den Kernmodul „.pm“ Pfad druckt nicht unbedingt den „cgi“ oder „.pl“ Skriptpfad, der ausgeführt wird. Ich denke, es hängt davon ab, was Ihr Ziel ist.

Es scheint mir, dass Cwd muss nur für mod_perl aktualisiert werden. Hier ist mein Vorschlag:

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;

Bitte fügen Sie alle Vorschläge.

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

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

Das Problem mit nur dirname(__FILE__) ist, dass es nicht Symlinks folgt. Ich hatte dies für meinen Skript zu verwenden, um die Symlink auf den tatsächlichen Speicherort der Datei zu folgen.

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

Alle Bibliothek freie Lösungen funktionieren nicht tatsächlich für mehr als ein paar Möglichkeiten, um einen Weg zu schreiben (man denke ../ oder /bla/x/../bin/./x/../ etc. Meine Lösung sieht unten wie ich habe eine Marotte:.. ich habe nicht die leiseste Ahnung, warum ich zweimal den Ersatz laufen muß, wenn ich nicht, ich bekomme eine unechte „./“ oder „../“ Neben. dass, wie es scheint recht robust zu mir.

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

Keiner der „top“ Antworten waren richtig für mich. Das Problem mit FindBin ‚$ Bin‘ oder Cwd ist, dass sie absoluten Pfad mit allen symbolischen Links aufgelöst zurückzukehren. In meinem Fall musste ich den genauen Pfad mit symbolischen Links vorhanden - das gleiche, wie Rückkehr Unix-Befehl „pwd“ und nicht „PWD -P“. Die folgende Funktion liefert die Lösung:

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

Was ist los mit $^X?

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

Möchten Sie geben den vollständigen Pfad zum Perl binäre Wesen verwendet wird.

Evert

Auf * nichts, haben Sie wahrscheinlich den „whereis“ Befehl, der sucht PATH $ für einen binäre mit einem bestimmten Namen suchen. Wenn $ 0 enthält nicht den vollständigen Pfadnamen, whereis $ skript ausgeführt und das Ergebnis in eine Variable Speichern sollte Ihnen sagen, wo sich das Skript befindet.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top