Comment puis-je obtenir le chemin complet vers un script Perl en cours d'exécution?

J'ai un script Perl et j'ai besoin de déterminer le chemin complet et le nom de fichier du script pendant l'exécution. J'ai découvert que selon la façon dont vous appelez le script $0 varie et contient parfois le {[1] } et parfois juste filename. Parce que le répertoire de travail peut également varier, Je ne peux pas penser à un moyen d'obtenir de manière fiable le fullpath+filename du script.

Quelqu'un a une solution?

150
demandé sur serenesat 2008-09-17 20:16:00

20 réponses

$ 0 est généralement le nom de votre programme, alors que diriez-vous de ceci?

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

Me Semble que cela doit fonctionner comme abs_path sait si vous utilisez un chemin relatif ou absolu.

Update pour ceux qui lisent cette année plus tard, vous devriez lire la réponse de Drew ci-dessous. C'est beaucoup mieux que le mien.

140
répondu Ovid 2017-08-22 16:19:21

Il y a plusieurs façons:

  • $0 est le script en cours d'exécution tel que fourni par POSIX, relatif au répertoire de travail en cours Si le script est au niveau ou en dessous de la CWD
  • en plus, cwd(), getcwd() et abs_path() sont fournis par le Cwd module et vous dire où le script est exécuté à partir de
  • Le module FindBin fournit l'$Bin & $RealBin les variables généralement sont le chemin à l'exécution du script; ce module fournit également $Script & $RealScript que le nom du script
  • __FILE__ est le fichier réel que l'interpréteur Perl traite pendant la compilation, y compris son chemin complet.

J'ai vu les trois premiers ($0, le Cwd module et le FindBin module) échoue sous mod_perl spectaculairement, produisant une sortie sans valeur telle que '.' ou une chaîne vide. Dans de tels environnements, j'utilise __FILE__ et obtenez le chemin de cela en utilisant l'File::Basename module:

use File::Basename;
my $dirname = dirname(__FILE__);
213
répondu Drew Stephens 2012-02-12 02:04:00
Use File::Spec;
File::Spec->rel2abs( __FILE__ );

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

34
répondu Mark 2013-08-19 21:32:17

Je pense que le module que vous recherchez est FindBin:

#!/usr/bin/perl
use FindBin;

$0 = "stealth";
print "The actual path to this is: $FindBin::Bin/$FindBin::Script\n";
16
répondu bmdhacks 2008-09-17 16:22:39

Vous pouvez utiliser FindBin, la Mdc, File::Basename, ou une combinaison d'entre eux. Ils sont tous dans la distribution de base de Perl IIRC.

J'ai utilisé Cwd dans le passé:

Cwd:

use Cwd qw(abs_path);
my $path = abs_path($0);
print "$path\n";
11
répondu Benjamin W. Smith 2008-10-08 07:13:28

Obtenir le chemin absolu $0 ou __FILE__ est ce que vous voulez. Le seul problème est que si quelqu'un a fait un chdir() et que le $0 était relatif-alors vous devez obtenir le chemin absolu dans un BEGIN{} pour éviter toute surprise.

FindBin essaie d'aller mieux et de ramper dans le $PATH pour quelque chose qui correspond au basename($0), mais il y a des moments où cela fait des choses beaucoup trop surprenantes (en particulier: lorsque le fichier est "juste en face de vous" dans le cwd.)

File::Fu a File::Fu->program_name et File::Fu->program_dir pour cela.

9
répondu Eric Wilhelm 2013-08-19 21:31:20

Un bref contexte:

Malheureusement, L'API Unix ne fournit pas un programme en cours d'exécution avec le chemin d'accès complet à l'exécutable. En fait, le programme exécutant le vôtre peut fournir ce qu'il veut dans le domaine qui indique normalement à votre programme ce qu'il est. Il y a, comme toutes les réponses le soulignent, diverses heuristiques pour trouver des candidats probables. Mais rien de moins que la recherche sur l'ensemble du système de fichiers fonctionnera toujours, et même cela échouera si l'exécutable est déplacé ou retiré.

Mais vous ne voulez pas l'exécutable Perl, qui est ce qui est réellement en cours d'exécution, mais le script qu'il exécute. Et Perl a besoin de savoir où le script est de le trouver. Il stocke ceci dans __FILE__, alors que $0 provient de L'API Unix. Cela peut toujours être un chemin relatif, alors prenez la suggestion de Mark et canonisez-la avec File::Spec->rel2abs( __FILE__ );

7
répondu wnoise 2013-08-19 21:30:49

Avez-vous essayé:

$ENV{'SCRIPT_NAME'}

Ou

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

Cela dépend vraiment de la façon dont il est appelé et s'il est CGI ou exécuté à partir d'un shell normal, etc.

6
répondu Sean 2008-09-17 16:21:33

Pour obtenir le chemin d'accès au répertoire contenant mon script que j'ai utilisé une combinaison de réponses déjà.

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

my $dir = dirname(File::Spec->rel2abs(__FILE__));
6
répondu Matt 2013-07-18 23:12:45

Perlfaq8 répond à une question très similaire en utilisant la fonction rel2abs() sur $0. Cette fonction peut être trouvée dans File::Spec.

2
répondu moritz 2013-08-19 21:31:57

Il N'est pas nécessaire d'utiliser des modules externes, avec une seule ligne, vous pouvez avoir le nom du fichier et le chemin relatif. Si vous utilisez des modules et que vous devez appliquer un chemin relatif au répertoire du script, le chemin relatif est suffisant.

$0 =~ m/(.+)[\/\\](.+)$/;
print "full path: $1, file name: $2\n";
2
répondu daniel souza 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
répondu mkc 2012-11-26 14:01:34

Vous cherchez ça?:

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

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

La sortie ressemblera à ceci:

You are running MyFileName.pl now.

Il fonctionne à la fois sur Windows et Unix.

1
répondu Yong Li 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
répondu Yordan Georgiev 2011-08-09 13:36:04

Le problème avec __FILE__ est qu'il imprimera le module de base ".pm" path pas nécessairement le".chemin de script cgi" ou ".pl " en cours d'exécution. Je suppose que cela dépend de votre objectif.

, Il me semble que Cwd juste besoin d'être mis à jour pour mod_perl. Voici ma suggestion:

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;

Veuillez ajouter des suggestions.

0
répondu Jonathan 2013-12-14 00:29:25

Sans modules externes, valable pour shell, fonctionne bien même avec '../':

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
0
répondu Putnik 2014-02-06 14:39:11

Le problème avec l'utilisation de dirname(__FILE__) est qu'il ne suit pas les liens symboliques. J'ai dû l'utiliser pour que mon script suive le lien symbolique vers l'emplacement du fichier réel.

use File::Basename;
my $script_dir = undef;
if(-l __FILE__) {
  $script_dir = dirname(readlink(__FILE__));
}
else {
  $script_dir = dirname(__FILE__);
}
0
répondu DavidG 2014-04-18 07:56:16

Toutes les solutions sans bibliothèque ne fonctionnent pas réellement pour plus de quelques façons d'écrire un chemin (pensez ../ ou /bla/x/../bac/./x/../ etc. Ma solution ressemble à ci-dessous. J'ai une bizarrerie: Je n'ai pas la moindre idée de pourquoi je dois exécuter les remplacements deux fois. Si Je ne le fais pas, je reçois un faux"./" ou "../". En dehors de cela, il me semble assez robuste.

  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
répondu Elmar 2014-09-04 10:32:56

Quel est le problème avec $^X ?

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

Vous donnerait le chemin complet vers le binaire Perl utilisé.

Evert

-1
répondu user3061015 2013-12-03 11:06:17

Sur * nix, vous avez probablement la commande "whereis", qui recherche votre $ PATH à la recherche d'un binaire avec un nom donné. Si $0 ne contient pas le nom de chemin complet, l'exécution de whereis $ scriptname et l'enregistrement du résultat dans une variable devraient vous indiquer où se trouve le script.

-5
répondu foxxtrot 2008-09-17 16:18:38