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


Tengo un script Perl y necesito determinar la ruta completa y el nombre de archivo del script 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 filename. Debido a que el directorio de trabajo también puede variar, no puedo pensar en una manera confiable de obtener el fullpath+filename del script.

Alguien tiene una solución?

Author: serenesat, 2008-09-17

20 answers

$0 es típicamente el nombre de su programa, así que ¿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 esto años más tarde, debe leer la respuesta de Drew a continuación. Es mucho mejor que el mío.

 140
Author: Ovid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-22 16:19:21

Hay algunas maneras:

  • $0 es el script que se está ejecutando actualmente como lo proporciona POSIX, relativo al directorio de trabajo actual si el script está en o por debajo del CWD
  • Además, cwd(), getcwd() and abs_path() are provided by the Cwd module and tell you where the script is being run from
  • El módulo FindBin proporciona la $Bin & $RealBin variables que normalmente son la ruta al script de ejecución; este módulo también proporciona $Script & $RealScript ese es el nombre del script
  • __FILE__ es el archivo real con el que el intérprete de Perl trata durante la compilación, incluyendo su ruta completa.

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

use File::Basename;
my $dirname = dirname(__FILE__);
 213
Author: Drew Stephens,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-12 02:04:00
Use File::Spec;
File::Spec->rel2abs( __FILE__ );

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

 34
Author: Mark,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-19 21:32:17

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";
 16
Author: bmdhacks,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-17 16:22:39

Podrías usar FindBin, Cwd, File:: Basename , o una combinación de ellos. Están todos 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";
 11
Author: Benjamin W. Smith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-08 07:13:28

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

FindBin intenta hacer algo mejor y arrastrarse en el $PATH para algo que coincida con el basename($0), pero hay veces en que eso hace cosas demasiado sorprendentes (específicamente: cuando el archivo está "justo en frente de usted" en el cwd.)

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

 9
Author: Eric Wilhelm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-19 21:31:20

Algunos antecedentes cortos:

Desafortunadamente 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 lo que es. Hay, como todas las respuestas señalan, 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 quitar.

Pero no quieres 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 todavía puede ser un camino relativo, así que toma la sugerencia de Mark y canonízala con File::Spec->rel2abs( __FILE__ );

 7
Author: wnoise,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-19 21:30:49

¿Has intentado:

$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 si se ejecuta desde un shell normal, etc.

 6
Author: Sean,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-17 16:21:33

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__));
 6
Author: Matt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-18 23:12:45

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

 2
Author: moritz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-19 21:31:57

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

$0 =~ m/(.+)[\/\\](.+)$/;
print "full path: $1, file name: $2\n";
 2
Author: daniel souza,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-01 16:19:13
#!/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

 1
Author: mkc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-26 14:01:34

¿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.

 1
Author: Yong Li,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-19 21:29:10
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 
 0
Author: Yordan Georgiev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-09 13:36:04

El problema con __FILE__ es que imprimirá la ruta del módulo principal ".pm" 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 sólo 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.

 0
Author: Jonathan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-14 00:29:25

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
 0
Author: Putnik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-06 14:39:11

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 real del archivo.

use File::Basename;
my $script_dir = undef;
if(-l __FILE__) {
  $script_dir = dirname(readlink(__FILE__));
}
else {
  $script_dir = dirname(__FILE__);
}
 0
Author: DavidG,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-18 07:56:16

Todas las soluciones libres de bibliotecas no funcionan realmente para más de unas pocas maneras de escribir una ruta (piense ../ o /bla/x/../recipiente/./x/../ sucesivamente. Mi solución se ve como abajo. Tengo una peculiaridad: no tengo la menor idea de por qué tengo que ejecutar los reemplazos dos veces. Si no lo hago, obtengo un espurio"./" 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/;
 0
Author: Elmar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-04 10:32:56

¿Qué tiene de malo $^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.

Evert

 -1
Author: user3061015,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-03 11:06:17

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

 -5
Author: foxxtrot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-17 16:18:38