Domanda

Ho uno script Perl e devo determinare il percorso completo e il nome file dello script durante l'esecuzione.L'ho scoperto a seconda di come chiami la sceneggiatura $0 varia e talvolta contiene il fullpath+filename e talvolta semplicemente filename.Poiché anche la directory di lavoro può variare, non riesco a pensare a un modo per ottenere in modo affidabile il file fullpath+filename della sceneggiatura.

Qualcuno ha una soluzione?

È stato utile?

Soluzione

Ci sono alcuni modi:

  • $0 è lo script attualmente in esecuzione fornito da POSIX, relativo alla directory di lavoro corrente se lo script si trova pari o inferiore a CWD
  • Inoltre, cwd(), getcwd() E abs_path() sono forniti da Cwd module e ti dice da dove viene eseguito lo script
  • Il modulo FindBin fornisce il $Bin & $RealBin variabili che Generalmente sono il percorso dello script in esecuzione;questo modulo fornisce anche $Script & $RealScript questo è il nome dello script
  • __FILE__ è il file effettivo con cui si occupa l'interprete Perl durante la compilazione, incluso il suo percorso completo.

Ho visto i primi tre ($0, IL Cwd modulo e il FindBin module) falliscono sotto mod_perl in modo spettacolare, producendo risultati senza valore come '.' o una stringa vuota.In tali ambienti, utilizzo __FILE__ e ottenere il percorso da quello utilizzando il file File::Basename modulo:

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

Altri suggerimenti

$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 dovrebbe funzionare poiché abs_path sa se stai utilizzando un percorso relativo o assoluto.

Aggiornamento Per chiunque legga questo articolo anni dopo, dovresti leggere la risposta di Drew di seguito.È molto meglio del mio.

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

Potresti usare TrovaBin, Cwd, File::Nomebase, 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 verso $0 O __FILE__ è quello che vuoi.L'unico problema è se qualcuno ha fatto a chdir() e il $0 era relativo, quindi devi ottenere il percorso assoluto in a BEGIN{} per evitare eventuali sorprese.

FindBin cerca di fare di meglio e strisciare nel $PATH per qualcosa che corrisponda a basename($0), ma ci sono momenti in cui ciò fa cose fin troppo sorprendenti (in particolare:quando il file è "proprio di fronte a te" nel cwd.)

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

Qualche breve background:

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

Ma non vuoi l'eseguibile Perl, che è ciò che è effettivamente in esecuzione, ma lo script che sta eseguendo.E Perl ha bisogno di sapere dove si trova lo script per trovarlo.Lo memorizza __FILE__, Mentre $0 proviene dall'API Unix.Questo può ancora essere un percorso relativo, quindi accetta il suggerimento di Mark e canonizzalo 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 eseguito da una shell normale, ecc.

Per ottenere il percorso della directory contenente il mio script ho utilizzato una combinazione di risposte già 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 con l'utilizzo di rel2abs() funzione attivata $0.Questa funzione può essere trovata in File::Spec.

Non è necessario utilizzare moduli esterni, con una sola riga puoi avere il nome del file e il relativo percorso.Se stai utilizzando moduli e devi applicare un percorso relativo alla directory dello 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 al seguente:

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/^(.*)(\\|\/)(.*)\.([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 

Il problema con __FILE__ è che stamperà il percorso ".pm" del modulo principale e non necessariamente il percorso dello script ".cgi" o ".pl" in esecuzione.Immagino che dipenda da quale sia il tuo obiettivo.

Mi sembra così Cwd deve solo 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 moduli esterni, 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 il solo utilizzo dirname(__FILE__) è che non segue i collegamenti simbolici.Ho dovuto usarlo affinché il mio script seguisse il collegamento simbolico alla posizione effettiva del file.

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

Tutte le soluzioni prive di libreria in realtà non funzionano più di alcuni modi per scrivere un percorso (pensa a ../ o /bla/x/../bin/./x/../ ecc.La mia soluzione appare come di seguito.Ho una curiosità:Non ho la più pallida idea del motivo per cui devo eseguire le sostituzioni due volte.In caso contrario, ottengo un "./" o "../" spurio.A parte questo mi sembra abbastanza robusto.

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

Nessuna delle risposte "migliori" era giusta per me.Il problema con l'utilizzo di FindBin '$Bin' o Cwd è che restituiscono il percorso assoluto con tutti i collegamenti simbolici risolti.Nel mio caso avevo bisogno del percorso esatto con collegamenti simbolici presenti, lo stesso che restituisce il comando Unix "pwd" e non "pwd -P".La seguente funzione fornisce la soluzione:

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

Cosa c'è che non va $^X ?

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

Ti fornirebbe il percorso completo del binario Perl utilizzato.

Evert

Su *nix, probabilmente hai il comando "whereis", che cerca nel tuo $PATH alla ricerca di un binario con un determinato nome.Se $0 non contiene il nome del percorso completo, l'esecuzione di whereis $scriptname e il salvataggio del risultato in una variabile dovrebbero dirti dove si trova lo script.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top