Как мне получить полный путь к исполняемому Perl-скрипту? - PullRequest
159 голосов
/ 17 сентября 2008

У меня есть сценарий Perl, и мне нужно определить полный путь и имя файла сценария во время выполнения. Я обнаружил, что в зависимости от того, как вы называете скрипт, $0 меняется и иногда содержит fullpath+filename, а иногда просто filename. Поскольку рабочий каталог также может различаться, я не могу придумать, как надежно получить fullpath+filename сценария.

Кто-нибудь получил решение?

Ответы [ 21 ]

228 голосов
/ 18 сентября 2008

Есть несколько способов:

  • $0 - это текущий исполняемый скрипт, предоставляемый POSIX, относительно текущего рабочего каталога, если скрипт находится на уровне CWD или ниже
  • Кроме того, cwd(), getcwd() и abs_path() предоставляются модулем Cwd и сообщают вам, откуда запускается скрипт
  • Модуль FindBin предоставляет переменные $Bin & $RealBin, которые обычно являются путем к исполняемому сценарию; этот модуль также предоставляет $Script & $RealScript, которые являются именем скрипта
  • __FILE__ - это файл, с которым интерпретатор Perl имеет дело во время компиляции, включая его полный путь.

Я видел первые три ($0, модуль Cwd и модуль FindBin) в разделе mod_perl впечатляюще, производя бесполезный вывод, такой как '.' или пустую строку. В таких средах я использую __FILE__ и получаю путь от него с помощью модуля File::Basename:

use File::Basename;
my $dirname = dirname(__FILE__);
143 голосов
/ 17 сентября 2008

$ 0, как правило, название вашей программы, так как насчет этого?

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

Мне кажется, это должно работать, так как abs_path знает, используете ли вы относительный или абсолютный путь.

Обновление Для тех, кто читает этот год спустя, вы должны прочитать ответ Дрю ниже. Это намного лучше, чем у меня.

34 голосов
/ 17 сентября 2008
Use File::Spec;
File::Spec->rel2abs( __FILE__ );

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

16 голосов
/ 17 сентября 2008

Я думаю, что модуль, который вы ищете - FindBin:

#!/usr/bin/perl
use FindBin;

$0 = "stealth";
print "The actual path to this is: $FindBin::Bin/$FindBin::Script\n";
11 голосов
/ 17 сентября 2008

Вы можете использовать FindBin , Cwd , File :: Basename или их комбинацию. Они все в базовом дистрибутиве Perl IIRC.

Я использовал Cwd в прошлом:

Cwd:

use Cwd qw(abs_path);
my $path = abs_path($0);
print "$path\n";
9 голосов
/ 18 сентября 2008

Получение абсолютного пути к $0 или __FILE__ - это то, что вы хотите. Единственная проблема в том, что если кто-то сделал chdir(), а $0 был относительным - тогда вам нужно получить абсолютный путь в BEGIN{}, чтобы предотвратить любые неожиданности.

FindBin пытается пойти еще лучше и потрогать в $PATH что-то, совпадающее с basename($0), но бывают случаи, когда это делает слишком удивительные вещи (в частности: когда файл "прямо перед вами "в cwd.)

File::Fu имеет File::Fu->program_name и File::Fu->program_dir для этого.

7 голосов
/ 17 сентября 2008

Краткий фон:

К сожалению, API Unix не предоставляет запущенной программе полный путь к исполняемому файлу. Фактически, исполняющая ваша программа может предоставить все, что она хочет в поле, которое обычно сообщает вашей программе, что это такое. Как указывают все ответы, существуют различные эвристические методы поиска вероятных кандидатов. Но ничего кроме поиска по всей файловой системе не всегда будет работать, и даже это не даст результата, если исполняемый файл будет перемещен или удален.

Но вам не нужен исполняемый файл Perl, который фактически выполняется, а сценарий, который он выполняет. И Perl должен знать, где находится скрипт, чтобы его найти. Он хранит это в __FILE__, а $0 из Unix API. Это все еще может быть относительный путь, поэтому возьмите предложение Марка и канонизируйте его с помощью File::Spec->rel2abs( __FILE__ );

6 голосов
/ 19 июля 2013

Чтобы получить путь к каталогу, содержащему мой сценарий, я использовал уже приведенную комбинацию ответов.

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

my $dir = dirname(File::Spec->rel2abs(__FILE__));
6 голосов
/ 17 сентября 2008

Вы пробовали:

$ENV{'SCRIPT_NAME'}

или

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

Это действительно зависит от того, как он вызывается и является ли он CGI или запускается из обычной оболочки и т. Д.

2 голосов
/ 17 сентября 2008

perlfaq8 отвечает на очень похожий вопрос с использованием функции rel2abs() в $0 Эту функцию можно найти в File :: Spec.

...