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?
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.
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()
etabs_path()
sont fournis par leCwd
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__);
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";
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";
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.
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__ );
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.
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__));
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";
#!/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
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.
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
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.
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
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__);
}
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/;
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
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.