¿Cómo obtengo la ruta completa a un script de Perl que se está ejecutando?

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

Alguien tiene una solución?

$ 0 es típicamente el nombre de su progtwig, 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á utilizando una ruta relativa o absoluta.

Actualización Para cualquiera que lea estos años más tarde, debería leer la respuesta de Drew a continuación. Es mucho mejor que el mío

Hay algunas maneras:

  • $0 es el script actualmente en ejecución 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 módulo Cwd y le indican dónde se está ejecutando el script desde
  • El módulo FindBin proporciona las variables $Bin y $RealBin que generalmente son la ruta al script de ejecución; este módulo también proporciona $Script & $RealScript que son el nombre del script
  • __FILE__ es el archivo real que el intérprete de Perl trata durante la comstackción, incluida su ruta completa.

He visto los primeros tres ( $0 , el módulo Cwd y el módulo FindBin ) fallar bajo mod_perl espectacular, produciendo resultados sin valor como '.' o una cadena vacía En dichos entornos, uso __FILE__ y obtengo la ruta a partir de eso usando el módulo File::Basename :

 use File::Basename; my $dirname = dirname(__FILE__); 
 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"; 

Puede usar FindBin , Cwd , File :: Basename , 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"; 

Obtener la ruta absoluta a $0 o __FILE__ es lo que desea. El único problema es que si alguien hizo un chdir() y el $0 era relativo, entonces necesita obtener el camino absoluto en BEGIN{} para evitar sorpresas.

FindBin intenta irse mejor y arrastrarse en $PATH para algo que coincida con el basename($0) , pero hay momentos en que eso hace cosas demasiado sorprendentes (específicamente: cuando el archivo está “justo enfrente de ti” en el cwd.)

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

Algunos antecedentes cortos:

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

Pero no desea el ejecutable de Perl, que es lo que realmente se está ejecutando, sino el script que está ejecutando. Y Perl necesita saber dónde está el script para encontrarlo. Almacena esto en __FILE__ , mientras que $0 es de la API de Unix. Esto aún puede ser una ruta relativa, así que tome la sugerencia de Mark y File::Spec->rel2abs( __FILE__ ); 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 llama y si es CGI o se ejecuta desde un shell normal, etc.

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

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

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

No es necesario usar módulos externos, con solo una línea puede tener el nombre de archivo y la ruta relativa. Si está utilizando módulos y necesita aplicar una ruta relativa al directorio de scripts, 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/^(.*)(\\|\/)(.*)\.([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 

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

Me parece que Cwd solo necesita ser actualizado 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 con solo 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 del archivo real.

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

Todas las soluciones libres de bibliotecas en realidad no funcionan para más de unas pocas formas de escribir una ruta (piense en ../ o /bla/x/../bin/./x/../ etc. Mi solución se parece a 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 falso “./” o “../”. 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/; 

¿Qué pasa con $^X ?

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

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

Evert

En * nix, es probable que tenga el comando “whereis”, que busca $ $ PATH en busca de un binario con un nombre de stack. Si $ 0 no contiene el nombre completo de la ruta, ejecutando whereis $ scriptname y guardando el resultado en una variable debería indicarte dónde está ubicado el script.