Как получить полный путь к Perl script, который выполняется?
У меня есть Perl script и вам нужно определить полный путь и имя файла script во время выполнения. Я обнаружил, что в зависимости от того, как вы называете script $0
, меняется и иногда содержит fullpath+filename
, а иногда просто filename
. Поскольку рабочий каталог также может меняться, я не могу представить способ надежного получения fullpath+filename
script.
Кто-нибудь получил решение?
Ответы
Ответ 1
Существует несколько способов:
-
$0
- это выполняемый в настоящее время script, предоставляемый POSIX, относительно текущего рабочего каталога, если script находится в или ниже CWD
- Кроме того,
cwd()
, getcwd()
и abs_path()
предоставляются модулем Cwd
и сообщают вам, где script выполняется из
- Модуль
FindBin
содержит переменные $Bin
и $RealBin
, которые обычно являются путем выполнения script; этот модуль также предоставляет $Script
и $RealScript
, которые являются именами script
-
__FILE__
- это фактический файл, с которым сталкивается интерпретатор Perl во время компиляции, включая полный путь.
Я видел первые три ($0
, Cwd
и FindBin
) не удается выполнить mod_perl
эффектно, производя бесполезный вывод, например '.'
или пустую строку. В таких средах я использую __FILE__
и получаю путь от этого с помощью File::Basename
:
use File::Basename;
my $dirname = dirname(__FILE__);
Ответ 2
$ 0, как правило, название вашей программы, так как насчет этого?
use Cwd 'abs_path';
print abs_path($0);
Мне кажется, это должно работать, так как abs_path знает, используете ли вы относительный или абсолютный путь.
Обновление Для тех, кто читает это несколько лет спустя, вы должны прочитать ответ Дрю. Это намного лучше, чем у меня.
Ответ 3
Use File::Spec;
File::Spec->rel2abs( __FILE__ );
http://perldoc.perl.org/File/Spec/Unix.html
Ответ 4
Я думаю, что модуль, который вы ищете, - FindBin:
#!/usr/bin/perl
use FindBin;
$0 = "stealth";
print "The actual path to this is: $FindBin::Bin/$FindBin::Script\n";
Ответ 5
Вы можете использовать FindBin, Cwd, File:: Basename или их комбинация. Все они находятся в базовом дистрибутиве Perl IIRC.
Я использовал Cwd в прошлом:
Cwd:
use Cwd qw(abs_path);
my $path = abs_path($0);
print "$path\n";
Ответ 6
Получение абсолютного пути к $0
или __FILE__
- это то, что вы хотите. Единственная проблема заключается в том, что кто-то сделал chdir()
и $0
относительный - тогда вам нужно получить абсолютный путь в BEGIN{}
, чтобы предотвратить любые неожиданности.
FindBin
пытается лучше разобраться в $PATH
для того, что соответствует basename($0)
, но бывают случаи, когда это делает слишком удивительные вещи (в частности: когда файл "прямо в перед вами" в cwd.)
File::Fu
имеет File::Fu->program_name
и File::Fu->program_dir
для этого.
Ответ 7
Короткий фон:
К сожалению, Unix API не предоставляет запущенной программе полный путь к исполняемому файлу. Фактически, исполняемая вами программа может предоставить все, что захочет, в поле, которое обычно сообщает вашей программе, что это такое. Есть, как и все ответы, различные эвристики для поиска вероятных кандидатов. Но ничего, кроме поиска всей файловой системы, всегда будет работать, и даже это не удастся, если исполняемый файл будет перемещен или удален.
Но вы не хотите, чтобы исполняемый файл Perl выполнялся, но выполнялся script. И Perl должен знать, где найти script. Он хранит это в __FILE__
, а $0
- из Unix API. Это может быть относительный путь, поэтому возьмите предложение Mark и канонизируйте его с помощью File::Spec->rel2abs( __FILE__ );
Ответ 8
Вы пробовали:
$ENV{'SCRIPT_NAME'}
или
use FindBin '$Bin';
print "The script is located in $Bin.\n";
Это действительно зависит от того, как он вызывается, и если он CGI или запускается из обычной оболочки и т.д.
Ответ 9
Чтобы получить путь к каталогу, содержащему мой script, я использовал комбинацию уже полученных ответов.
#!/usr/bin/perl
use strict;
use warnings;
use File::Spec;
use File::Basename;
my $dir = dirname(File::Spec->rel2abs(__FILE__));
Ответ 10
perlfaq8 отвечает на очень похожий вопрос с использованием функции rel2abs()
на $0
. Эта функция может быть найдена в файле:: Spec.
Ответ 11
Нет необходимости использовать внешние модули, и только одна строка может содержать имя файла и относительный путь. Если вы используете модули и вам необходимо применить путь к каталогу script, то относительный путь будет достаточным.
$0 =~ m/(.+)[\/\\](.+)$/;
print "full path: $1, file name: $2\n";
Ответ 12
Вы ищете это?:
my $thisfile = $1 if $0 =~
/\\([^\\]*)$|\/([^\/]*)$/;
print "You are running $thisfile
now.\n";
Результат будет выглядеть так:
You are running MyFileName.pl now.
Он работает как с Windows, так и с Unix.
Ответ 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
Ответ 14
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 \ to / 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
Ответ 15
Проблема с __FILE__
заключается в том, что он будет печатать основной модуль ".pm" не обязательно в запущенном пути ".cgi" или ".pl" script. Я думаю, это зависит от вашей цели.
Мне кажется, что 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;
Пожалуйста, добавьте любые предложения.
Ответ 16
Без каких-либо внешних модулей, действительных для оболочки, хорошо работает даже с '../':
my $self = `pwd`;
chomp $self;
$self .='/'.$1 if $0 =~/([^\/]*)$/; #keep the filename only
print "self=$self\n";
Тест:
$ /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
Ответ 17
Проблема с использованием dirname(__FILE__)
заключается в том, что она не соответствует символическим ссылкам. Мне пришлось использовать это для моего script, чтобы следовать символической ссылке в фактическое местоположение файла.
use File::Basename;
my $script_dir = undef;
if(-l __FILE__) {
$script_dir = dirname(readlink(__FILE__));
}
else {
$script_dir = dirname(__FILE__);
}
Ответ 18
Все библиотечные решения на самом деле не работают более чем несколькими способами для написания пути (подумайте../или/bla/x/../bin/./x/../и т.д. My решение выглядит следующим образом: у меня есть одна причуда: у меня нет ни малейшего представления о том, почему я должен дважды запускать замены. Если я этого не сделаю, я получаю ложные "./" или "../". это кажется мне довольно надежным.
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/;
Ответ 19
Ни один из "лучших" ответов не был для меня правильным. Проблема с использованием FindBin '$ Bin' или Cwd заключается в том, что они возвращают абсолютный путь со всеми разрешенными символическими ссылками. В моем случае мне нужен был точный путь с символическими ссылками - так же, как возвращает Unix команду "pwd", а не "pwd -P". Следующая функция обеспечивает решение:
sub get_script_full_path {
use File::Basename;
use File::Spec;
use Cwd qw(chdir cwd);
my $curr_dir = cwd();
chdir(dirname($0));
my $dir = $ENV{PWD};
chdir( $curr_dir);
return File::Spec->catfile($dir, basename($0));
}
Ответ 20
В Windows совместное использование dirname
и abs_path
лучше для меня.
use File::Basename;
use Cwd qw(abs_path);
# absolute path of the directory containing the executing script
my $abs_dirname = dirname(abs_path($0));
print "\ndirname(abs_path(\$0)) -> $abs_dirname\n";
вот почему:
# this gives the answer I want in relative path form, not absolute
my $rel_dirname = dirname(__FILE__);
print "dirname(__FILE__) -> $rel_dirname\n";
# this gives the slightly wrong answer, but in the form I want
my $full_filepath = abs_path($0);
print "abs_path(\$0) -> $full_filepath\n";
Ответ 21
Что случилось с $^X
?
#!/usr/bin/env perl<br>
print "This is executed by $^X\n";
Дает вам полный путь к используемому двоичному файлу Perl.
Эверт
Ответ 22
В * nix у вас, вероятно, есть команда "whereis", которая ищет ваш PATH, ищущий двоичный файл с заданным именем. Если $0 не содержит полного имени пути, запуск whereis $scriptname и сохранение результата в переменной должен указать вам, где находится script.