Как получить полный путь к скрипту Perl, который выполняется?
у меня есть скрипт на Perl, и нужно определить полный путь и имя файла скрипта во время выполнения. Я обнаружил, что в зависимости от того, как вы вызываете скрипт меняется и иногда содержит
fullpath+filename
а иногда просто filename
. Потому что рабочий каталог может меняться, а я не могу придумать способ надежно получить fullpath+filename
скрипта.
у кого-нибудь есть решение?
20 ответов:
$0-это обычно Название вашей программы, так как насчет этого?
use Cwd 'abs_path'; print abs_path();
Мне кажется, что это должно работать как abs_path знает, если вы используете относительный или абсолютный путь.
обновление для тех, кто читает это годы спустя, вы должны прочитать ответ Дрю ниже. Это намного лучше, чем у меня.
есть несколько способов:
является ли текущий выполняемый скрипт, предоставленный POSIX, относительно текущего рабочего каталога, если скрипт находится на уровне или ниже CWD
- кроме того,
cwd()
,getcwd()
иabs_path()
предусмотреныCwd
модуль и сказать вам, где скрипт запускается из- модуль
FindBin
предоставляет$Bin
&$RealBin
переменные, которые обычно - это путь к исполняемому скрипту; этот модуль также предоставляет$Script
&$RealScript
имя скрипта__FILE__
- это фактический файл, который интерпретатор Perl обрабатывает во время компиляции, включая его полный путь.Я видел первые три (
на
Cwd
иFindBin
модуль) проваливаются подmod_perl
эффектно, производство бесполезной продукции, такой как'.'
или пустая строка. В таких условиях, я использую__FILE__
и получить путь от этого с помощьюFile::Basename
модуль:use File::Basename; my $dirname = dirname(__FILE__);
Я думаю, что модуль, который вы ищете, это FindBin:
#!/usr/bin/perl use FindBin; = "stealth"; print "The actual path to this is: $FindBin::Bin/$FindBin::Script\n";
вы могли бы использовать FindBin, Cwd,File:: Basename, или их сочетание. Все они находятся в базовом распределении Perl IIRC.
Я использовал Cwd в прошлом:
Cwd:
use Cwd qw(abs_path); my $path = abs_path(); print "$path\n";
получение абсолютного пути к
или
__FILE__
это то, что вы хотите. Единственная проблема-если кто-то сделалchdir()
ибыл относительным, тогда вам нужно получить абсолютный путь в
BEGIN{}
чтобы предотвратить любые сюрпризы.
FindBin
пытается идти один лучше и пресмыкаться в$PATH
для чего-то, соответствующегоbasename()
, но бывают случаи, когда это делает слишком удивительные вещи (в частности: когда файл находится "прямо перед вами" в cwd.)
File::Fu
иFile::Fu->program_name
иFile::Fu->program_dir
для этого.
несколько коротких справочная информация:
к сожалению, UNIX API не предоставляет запущенную программу с полным путем к исполняемому файлу. Фактически, программа, выполняющая вашу, может предоставить все, что она хочет в поле, которое обычно говорит вашей программе, что это такое. Существуют, как указывают все ответы, различные эвристики для поиска вероятных кандидатов. Но ничего, кроме поиска всей файловой системы, всегда будет работать, и даже это не удастся, если исполняемый файл будет перемещен или удаленный.
но вы не хотите исполняемый файл Perl, который на самом деле работает, но скрипт, который он выполняет. И Perl должен знать, где находится скрипт, чтобы найти его. Он хранит это в
__FILE__
, аиз UNIX API. Это все еще может быть относительный путь, поэтому примите предложение Марка и канонизируйте его с помощью
File::Spec->rel2abs( __FILE__ );
вы пробовали:
$ENV{'SCRIPT_NAME'}
или
use FindBin '$Bin'; print "The script is located in $Bin.\n";
это действительно зависит от того, как он вызывается, и если это CGI или запускается из обычной оболочки и т. д.
для того, чтобы получить путь к каталогу, содержащему мой скрипт я использовал комбинацию ответов уже даны.
#!/usr/bin/perl use strict; use warnings; use File::Spec; use File::Basename; my $dir = dirname(File::Spec->rel2abs(__FILE__));
perlfaq8 ответ на очень похожий вопрос с помощью на
. Эту функцию можно найти в файле::Spec.
нет необходимости использовать внешние модули, только с одной строкой вы можете иметь имя файла и относительный путь. Если вы используете модули и вам нужно применить путь относительно каталога скрипта, относительного пути достаточно.
=~ m/(.+)[\/\](.+)$/; print "full path: , file name: \n";
#!/usr/bin/perl -w use strict; my $path = ; $path =~ s/\.\///g; if ($path =~ /\//){ if ($path =~ /^\//){ $path =~ /^((\/[^\/]+){1,}\/)[^\/]+$/; $path = ; } else { $path =~ /^(([^\/]+\/){1,})[^\/]+$/; my $path_b = ; 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
вы ищете это?:
my $thisfile = if =~ /\([^\]*)$|\/([^\/]*)$/; print "You are running $thisfile now.\n";
вывод будет выглядеть так:
You are running MyFileName.pl now.
Он работает как на Windows, так и на 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 = ; #debug print "$1 is \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
проблема с
__FILE__
это то, что он будет печатать основной модуль ".pm" путь не обязательно ".CGI" или". pl " путь сценария, который выполняется. Я думаю, это зависит от того, какова ваша цель.мне кажется, что
Cwd
просто нужно обновить для mod_perl. Вот мое предложение: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;
пожалуйста, добавьте любые предложения.
без каких-либо внешних модулей, действительных для оболочки, хорошо работает даже с '../':
my $self = `pwd`; chomp $self; $self .='/'. if =~/([^\/]*)$/; #keep the filename only print "self=$self\n";
проблема только с использованием
dirname(__FILE__)
это то, что он не следует символическим ссылкам. Я должен был использовать это для моего скрипта, чтобы следовать символической ссылке на фактическое местоположение файла.use File::Basename; my $script_dir = undef; if(-l __FILE__) { $script_dir = dirname(readlink(__FILE__)); } else { $script_dir = dirname(__FILE__); }
все решения без библиотек на самом деле не работают более чем на несколько способов написания пути (подумайте ../ или / бла / х/../закром.//икс././ прием. Мое решение выглядит следующим образом. У меня есть одна причуда: я не имею ни малейшего представления, почему я должен запускать замены дважды. Если я этого не сделаю, я получу поддельный "./" или." ./". Кроме того, он кажется мне довольно прочным.
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/(.*)\/([^\/]+)//;