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

StackOverflow https://stackoverflow.com/questions/84932

  •  01-07-2019
  •  | 
  •  

Question

J'ai un script Perl et je dois déterminer le chemin complet et le nom du fichier du script pendant son exécution. J'ai découvert que, selon la façon dont vous appelez le script $ 0 , il contient parfois le chemin complet + nom de fichier et parfois simplement nom de fichier . Comme le répertoire de travail peut également varier, je ne vois pas comment obtenir de manière fiable le chemin complet + nom de fichier du script.

Quelqu'un a une solution?

Était-ce utile?

La solution

Il y a plusieurs moyens:

  • $ 0 est le script en cours d'exécution tel que fourni par POSIX, par rapport au répertoire de travail actuel si le script est égal ou inférieur à CWD
  • De plus, cwd () , getcwd () et abs_path () sont fournis par Cwd et vous indique d'où le script est exécuté
  • Le module FindBin fournit le $ Bin & amp; $ RealBin variables qui habituellement constituent le chemin d'accès au script en cours d'exécution; Ce module fournit également $ Script & amp; $ RealScript qui sont le nom du script
  • __ FICHIER __ est le fichier réel que le L’interprète Perl s’occupe de la compilation, y compris de son chemin complet.

J'ai vu les trois premiers ( 0 $ , le module Cwd et le module FindBin ) échoue de manière spectaculaire sous mod_perl , produisant des résultats sans valeur tels que '.' ou une chaîne vide. Dans de tels environnements, j'utilise __ FICHIER __ et je reçois le chemin à partir de celui-ci en utilisant le module Fichier :: Nom :: :

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

Autres conseils

$ 0 est généralement le nom de votre programme, pourquoi pas cela?

use Cwd 'abs_path';
print abs_path(<*>);

Il me semble que cela devrait fonctionner puisque abs_path sait si vous utilisez un chemin relatif ou absolu.

Mise à jour Si vous lisez ceci quelques années plus tard, vous devriez lire la réponse de Drew ci-dessous. C'est beaucoup mieux que le mien.

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

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

Je pense que le module que vous recherchez est FindBin:

#!/usr/bin/perl
use FindBin;

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

Vous pouvez utiliser FindBin , Cwd , File :: Basename , ou une combinaison de ceux-ci. Ils sont tous dans la distribution de base de Perl IIRC.

J'ai déjà utilisé Cwd:

Cwd:

use Cwd qw(abs_path);
my $path = abs_path(<*>);
print "$path\n";

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

FindBin essaie de faire mieux et de ramper dans le $ PATH pour obtenir un résultat correspondant à nom de base ($ 0) , mais il y a des moments quand cela fait des choses bien trop surprenantes (en particulier: quand le fichier est "juste devant vous" dans le dossier.)

File :: Fu a File :: Fu- > nom_programme et File :: Fu- > programme_dir pour cela.

Quelques informations de base:

Malheureusement, l'API Unix ne fournit pas de programme en cours d'exécution avec le chemin d'accès complet à l'exécutable. En fait, le programme qui exécute le vôtre peut fournir ce qu'il veut sur le terrain, qui indique normalement à votre programme ce que c'est. Comme toutes les réponses le soulignent, il existe diverses heuristiques pour trouver des candidats probables. Mais rien ne pourra se passer de chercher dans l’ensemble du système de fichiers et cela échouera même si l’exécutable est déplacé ou supprimé.

Mais vous ne voulez pas l'exécutable Perl, qui est ce qui est en train de tourner, mais le script qu'il exécute. Et Perl a besoin de savoir où se trouve le script pour le trouver. Il stocke cela dans __ FILE __ , tandis 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__);

Avez-vous essayé:

$ENV{'SCRIPT_NAME'}

ou

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

Cela dépend vraiment de la manière dont il est appelé, de son exécution CGI ou de son exécution à partir d'un shell normal, etc.

Afin d’obtenir le chemin du répertoire contenant mon script, j’ai déjà utilisé une combinaison de réponses.

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

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

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

Il n’est pas nécessaire d’utiliser des modules externes: avec une seule ligne, vous pouvez avoir le nom de fichier et le chemin relatif. Si vous utilisez des modules et devez appliquer un chemin relatif au répertoire du script, celui-ci suffit.

<*> =~ m/(.+)[\/\\](.+)$/;
print "full path: $1, file name: $2\n";
#!/usr/bin/perl -w
use strict;


my $path = <*>;
$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

Cherchez-vous cela?:

my $thisfile = $1 if 
You are running MyFileName.pl now.
=~ /\\([^\\]*)$|\/([^\/]*)$/; print "You are running $thisfile now.\n";

La sortie ressemblera à ceci:

<*>

Cela fonctionne à la fois sous Windows et sous 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(<*>) ; 
        #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 

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

Il me semble que Cwd seulement doit ê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;

Ajoutez des suggestions.

Sans aucun module externe, valable pour le shell, fonctionne bien même avec '../':

my $self = `pwd`;
chomp $self;
$self .='/'.$1 if 
$ /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
=~/([^\/]*)$/; #keep the filename only print "self=$self\n";

test:

<*>

Le seul problème avec l’utilisation de dirname (__ FILE __) est qu’il ne suit pas les liens symboliques. Je devais l'utiliser pour que mon script suive le lien symbolique vers l'emplacement actuel du fichier.

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

Toutes les solutions sans bibliothèque ne fonctionnent en réalité que pour quelques façons d'écrire un chemin (pensez ../ ou /bla/x/../bin/./x/../ etc. La solution ressemble à celle ci-dessous. J'ai un problème: je ne sais pas du tout pourquoi je dois exécuter les remplacements deux fois. En dehors de cela, cela me semble assez robuste.

  my $callpath = <*>;
  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/;

Aucun des "haut" " les réponses étaient exactes pour moi. Le problème avec FindBin '$ Bin' ou Cwd est qu’ils renvoient un chemin absolu avec tous les liens symboliques résolus. Dans mon cas, j'avais besoin du chemin exact avec les liens symboliques présents - identique à celui qui renvoie la commande Unix " pwd " et non "pwd -P". La fonction suivante fournit la solution:

sub get_script_full_path {
    use File::Basename;
    use File::Spec;
    use Cwd qw(chdir cwd);
    my $curr_dir = cwd();
    chdir(dirname(<*>));
    my $dir = $ENV{PWD};
    chdir( $curr_dir);
    return File::Spec->catfile($dir, basename(<*>));
}

Qu'est-ce qui ne va pas avec $ ^ X ?

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

Vous donnerait le chemin complet du binaire Perl utilisé.

Evert

Sur * nix, vous avez probablement le " whereis " commande qui recherche dans votre $ PATH un binaire portant un nom donné. Si $ 0 ne contient pas le nom du chemin complet, exécuter whereis $ scriptname et enregistrer le résultat dans une variable doivent vous indiquer l'emplacement du script.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top