Pregunta

Tengo un script Perl y necesito determinar la ruta completa y el nombre del archivo del script durante la ejecución.Descubrí que dependiendo de cómo llames al guión $0 varía y a veces contiene la fullpath+filename y a veces solo filename.Debido a que el directorio de trabajo también puede variar, no puedo pensar en una manera de obtener el directorio de manera confiable. fullpath+filename del guion.

¿Alguien tiene una solución?

¿Fue útil?

Solución

Hay algunas maneras:

  • $0 es el script que se está ejecutando actualmente según lo proporcionado por POSIX, en relación con el directorio de trabajo actual si el script está en o debajo del CWD
  • Además, cwd(), getcwd() y abs_path() son proporcionados por el Cwd módulo y le indicará desde dónde se ejecuta el script
  • El módulo FindBin proporciona el $Bin & $RealBin variables que generalmente son la ruta al script en ejecución;este módulo también proporciona $Script & $RealScript ese es el nombre del script
  • __FILE__ es el archivo real con el que trata el intérprete de Perl durante la compilación, incluida su ruta completa.

He visto los primeros tres ($0, el Cwd módulo y el FindBin módulo) falla bajo mod_perl espectacularmente, produciendo productos sin valor como '.' o una cadena vacía.En tales entornos, uso __FILE__ y obtener el camino desde eso usando el File::Basename módulo:

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

Otros consejos

$0 suele ser el nombre de su programa, entonces, ¿qué tal esto?

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

Me parece que esto debería funcionar ya que abs_path sabe si estás usando una ruta relativa o absoluta.

Actualizar Cualquiera que lea esto años después, debería leer la respuesta de Drew a continuación.Es mucho mejor que el mío.

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

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

Creo que el módulo que estás buscando es FindBin:

#!/usr/bin/perl
use FindBin;

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

Podrías usar BuscarBin, CWD, Archivo::Nombre base, o una combinación de ellos.Todos están en la distribución base de Perl IIRC.

Usé Cwd en el pasado:

Cwd:

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

Obteniendo el camino absoluto hacia $0 o __FILE__ es lo que quieres.El único problema es que si alguien hiciera un chdir() y el $0 era relativo, entonces necesitas obtener la ruta absoluta en un BEGIN{} para evitar sorpresas.

FindBin trata de mejorar y arrastrarse en el $PATH por algo que coincida con basename($0), pero hay ocasiones en las que eso produce cosas demasiado sorprendentes (específicamente:cuando el archivo está "justo frente a usted" en el cwd.)

File::Fu tiene File::Fu->program_name y File::Fu->program_dir para esto.

Algunos breves antecedentes:

Lamentablemente, la API de Unix no proporciona un programa en ejecución con la ruta completa al ejecutable.De hecho, el programa que ejecuta el suyo puede proporcionar lo que quiera en el campo que normalmente le dice a su programa qué es.Como señalan todas las respuestas, existen varias heurísticas para encontrar candidatos probables.Pero nada menos que buscar en todo el sistema de archivos siempre funcionará, e incluso eso fallará si el ejecutable se mueve o elimina.

Pero no desea el ejecutable de Perl, que es lo que realmente se está ejecutando, sino el script que se está ejecutando.Y Perl necesita saber dónde está el script para encontrarlo.Almacena esto en __FILE__, mientras $0 es de la API de Unix.Este todavía puede ser un camino relativo, así que toma la sugerencia de Marcos y canonízalo con File::Spec->rel2abs( __FILE__ );

Has probado:

$ENV{'SCRIPT_NAME'}

o

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

Realmente depende de cómo se llame y si es CGI o se ejecuta desde un shell normal, etc.

Para obtener la ruta al directorio que contiene mi script, utilicé una combinación de respuestas ya dadas.

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

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

perlfaq8 responde a una pregunta muy similar con el uso de rel2abs() funcionar en $0.Esa función se puede encontrar en File::Spec.

No es necesario utilizar módulos externos, con solo una línea puedes tener el nombre del archivo y la ruta relativa.Si está utilizando módulos y necesita aplicar una ruta relativa al directorio del script, la ruta relativa es suficiente.

$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

¿Estás buscando esto?:

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

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

La salida se verá así:

You are running MyFileName.pl now.

Funciona tanto en Windows como en 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 

El problema con __FILE__ es que imprimirá la ruta ".pm" del módulo principal, no necesariamente la ruta del script ".cgi" o ".pl" que se está ejecutando.Supongo que depende de cuál sea tu objetivo.

Me parece que Cwd solo necesita actualizarse para mod_perl.Aquí está mi sugerencia:

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;

Por favor agregue cualquier sugerencia.

Sin ningún módulo externo, válido para shell, funciona bien incluso con '../':

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

prueba:

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

El problema de simplemente usar dirname(__FILE__) es que no sigue enlaces simbólicos.Tuve que usar esto para que mi script siguiera el enlace simbólico a la ubicación real del archivo.

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

Todas las soluciones sin biblioteca en realidad no funcionan para más que unas pocas formas de escribir una ruta (piense ../ o /bla/x/../bin/./x/../ etc.Mi solución se ve a continuación.Tengo una peculiaridad:No tengo la menor idea de por qué tengo que ejecutar los reemplazos dos veces.Si no lo hago, obtengo un "./" o "../" falso.Aparte de eso, me parece bastante 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/;

Ninguna de las respuestas "principales" era adecuada para mí.El problema con el uso de FindBin '$Bin' o Cwd es que devuelven una ruta absoluta con todos los enlaces simbólicos resueltos.En mi caso, necesitaba la ruta exacta con enlaces simbólicos presentes, lo mismo que devuelve el comando de Unix "pwd" y no "pwd -P".La siguiente función proporciona la solución:

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

Qué hay de malo en $^X ?

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

Le daría la ruta completa al binario de Perl que se está utilizando.

evertir

En *nix, es probable que tenga el comando "whereis", que busca en su $PATH un binario con un nombre determinado.Si $0 no contiene el nombre de ruta completo, ejecutar whereis $scriptname y guardar el resultado en una variable debería indicarle dónde se encuentra el script.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top