Come posso ottenere il percorso completo per uno script Perl in esecuzione?

Ho lo script Perl e ho bisogno di determinare il percorso completo e il nome del file dello script durante l’esecuzione. Ho scoperto che a seconda di come si chiama lo script $0 varia e talvolta contiene il percorso fullpath+filename e talvolta solo il filename . Poiché anche la directory di lavoro può variare, non riesco a pensare ad un modo per ottenere in modo affidabile il percorso fullpath+filename dello script.

Qualcuno ha una soluzione?

$ 0 è in genere il nome del tuo programma, quindi che ne dici di questo?

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

Mi sembra che questo dovrebbe funzionare come abs_path sa se stai usando un percorso relativo o assoluto.

Aggiornamento Per tutti coloro che leggono questi anni dopo, dovresti leggere la risposta di Drew sotto. È molto meglio del mio

Ci sono alcuni modi:

  • $0 è lo script attualmente in esecuzione come fornito da POSIX, relativo alla directory di lavoro corrente se lo script è uguale o inferiore al CWD
  • Inoltre, cwd() , getcwd() e abs_path() sono forniti dal modulo Cwd e indicano dove viene eseguito lo script da
  • Il modulo FindBin fornisce le variabili $Bin e $RealBin che di solito sono il percorso dello script in esecuzione; questo modulo fornisce anche $Script e $RealScript che sono il nome dello script
  • __FILE__ è il file effettivo che l’interprete Perl gestisce durante la compilazione, compreso il percorso completo.

Ho visto i primi tre ( $0 , il modulo Cwd e il modulo FindBin ) fallire sotto mod_perl spettacolare, producendo output senza valore come '.' o una stringa vuota. In tali ambienti, utilizzo __FILE__ e ottengo il percorso da quello utilizzando il modulo File::Basename :

 use File::Basename; my $dirname = dirname(__FILE__); 
 Use File::Spec; File::Spec->rel2abs( __FILE__ ); 

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

Penso che il modulo che stai cercando sia FindBin:

 #!/usr/bin/perl use FindBin; $0 = "stealth"; print "The actual path to this is: $FindBin::Bin/$FindBin::Script\n"; 

È ansible utilizzare FindBin , Cwd , File :: Basename o una combinazione di essi. Sono tutti nella distribuzione base di Perl IIRC.

Ho usato Cwd in passato:

Cwd:

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

Ottenere il percorso assoluto per $0 o __FILE__ è quello che vuoi. L’unico problema è che se qualcuno ha fatto un chdir() e $0 era relativo – allora è necessario ottenere il percorso assoluto in un BEGIN{} per evitare sorprese.

FindBin prova ad andare meglio e si aggira nel $PATH per qualcosa che corrisponde al basename($0) , ma ci sono momentjs in cui ciò fa cose troppo sorprendenti (in particolare: quando il file è “proprio di fronte a te” in il cwd.)

File::Fu ha File::Fu->program_name e File::Fu->program_dir per questo.

Qualche breve background:

Sfortunatamente l’API Unix non fornisce un programma in esecuzione con il percorso completo dell’eseguibile. Infatti, il programma che esegue il tuo può fornire tutto ciò che vuole nel campo che normalmente dice al tuo programma di cosa si tratta. Vi sono, come sottolineano tutte le risposte, varie euristiche per trovare probabili candidati. Ma qualsiasi ricerca nell’intero filesystem funzionerà sempre, e anche quella fallirà se l’eseguibile viene spostato o rimosso.

Ma tu non vuoi che l’eseguibile di Perl, che è ciò che è in realtà in esecuzione, ma lo script che sta eseguendo. E Perl deve sapere dov’è lo script per trovarlo. Memorizza questo in __FILE__ , mentre $0 proviene dall’API Unix. Questo può ancora essere un percorso relativo, quindi prendi il suggerimento di Marco e canonizzalo con File::Spec->rel2abs( __FILE__ );

Hai provato:

 $ENV{'SCRIPT_NAME'} 

o

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

Dipende davvero da come viene chiamato e se è CGI o viene eseguito da una shell normale, ecc.

Per ottenere il percorso verso la directory che contiene il mio script ho usato già una combinazione di risposte fornite.

 #!/usr/bin/perl use strict; use warnings; use File::Spec; use File::Basename; my $dir = dirname(File::Spec->rel2abs(__FILE__)); 

perlfaq8 risponde a una domanda molto simile usando la funzione rel2abs() su $0 . Questa funzione può essere trovata in File :: Spec.

Non è necessario utilizzare moduli esterni, con solo una riga è ansible avere il nome del file e il percorso relativo. Se stai usando i moduli e hai bisogno di applicare un percorso relativo alla directory degli script, il percorso relativo è sufficiente.

 $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

Stai cercando questo ?:

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

L’output sarà simile a questo:

 You are running MyFileName.pl now. 

Funziona sia su Windows che su 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/^(.*)(\\|\/)(.*)\.([az]*)/; $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 

Il problema con __FILE__ è che stamperà il percorso “.pm” del modulo principale non necessariamente il percorso di script “.cgi” o “.pl” in esecuzione. Immagino dipenda da quale sia il tuo objective.

Mi sembra che Cwd solo bisogno di essere aggiornato per mod_perl. Ecco il mio suggerimento:

 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; 

Si prega di aggiungere eventuali suggerimenti.

Senza alcun modulo esterno, valido per shell, funziona bene anche con ‘../’:

 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 

Il problema con l’uso di dirname(__FILE__) è che non segue i collegamenti simbolici. Ho dovuto usare questo per il mio script per seguire il link simbolico alla posizione del file reale.

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

Tutte le soluzioni libere da libreria non funzionano più di alcuni modi per scrivere un percorso (si pensi ../o /bla/x/../bin/./x/../ ecc. La mia soluzione sembra Di seguito ho una stranezza: non ho la più pallida idea del motivo per cui devo eseguire le sostituzioni due volte. Se non lo faccio, ottengo uno spurio “./” o “../”. A parte questo, sembra abbastanza robusto per me.

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

Cosa c’è di sbagliato con $^X ?

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

Ti darebbe il percorso completo per il binario Perl utilizzato.

rovesciare

Su * nix, probabilmente hai il comando “whereis”, che ricerca il tuo $ PATH alla ricerca di un binario con un nome specifico. Se $ 0 non contiene il nome completo del percorso, eseguire whereis $ scriptname e salvare il risultato in una variabile dovrebbe dirti dove si trova lo script.