Вызов script с тем же @INC, что и родительский script

Я хочу вызвать внешний script с помощью system ($script) или do $script. В моем @INC у меня есть некоторые определенные модули, которые я импортирую. Как я могу вызвать $script и передать ему тот же @INC?

Script1.pm

#importing some libs
#code
$script = "path_to_script";

system ($script);

Script2.pm

use [email protected];

И я получаю сообщение об ошибке:

Невозможно найти LibFromScript1 в @INC...

Ответ 1

Самый простой способ - установить переменную среды PERL5LIB. Это добавит список каталогов в дочерний процесс @INC array

Ваш код выглядел бы как

$ENV{PERL5LIB} = join ':', @INC;

system $script;

Это имеет тот недостаток, что стандартные каталоги также будут добавлены в @INC. Это не должно вызывать никаких проблем, но было бы лучше установить PERL5LIB только в пользовательские каталоги, если вы их знаете в этот момент.

Обратите внимание, что perl будет игнорировать PERL5LIB, если вы работаете под флагом taint.

Ответ 2

Строго отвечая на ваш вопрос, вы могли бы do $script;, хотя рекомендуемый способ состоял бы в том, чтобы разделить вашу общую программную логику на модуль и use/require.

Ответ 3

Вы можете использовать Storable для сохранения @INC в файле, а затем выбрать его в другом script.

Например, вы можете сделать что-то вроде ниже.

test.pl

#!/usr/bin/perl
use strict;
use warnings;
use Storable;
store (\@INC, "test2.dump") or die "could not store";
system("perl", "test2.pl", $$) == 0 or die "error";

test2.pl

#!/usr/bin/perl
use strict;
use warnings;
use Storable;
use Data::Dumper;
my $parentpid = shift;
my $ref = retrieve("test2.dump") or die "couldn't retrieve";
print Dumper $ref;

Как только вы получите @INC в test2.pl как $ref, вы можете изменить @INC в test2.pl, чтобы взять содержимое из $ref.

Ответ 4

Вопрос о том, как использовать одни и те же модули в нескольких сценариях. Координация их @INC составляет лишь половину проблемы, и я бы предложил использовать PERL5LIB, как в ответе Бородина. Затем те же модули также должны быть загружены в оба сценария.

Для этого мы можем написать модуль утилиты, который загружает все эти общие модули, а затем просто use в обеих программах. Это непросто сделать правильно, но для него есть хороший модуль, Import:: Into

Файл CommonModules.pm

package CommonModules;

use warnings;
use strict;
use feature ':5.10';

use Import::Into;

sub import
{
    my ($package, @args) = @_;   # can pass arguments normally

    my $target = caller;

    warnings->import::into($target);
    strict  ->import::into($target);
    feature ->import::into($target, ':5.10');

    Getopt::Long->import::into($target);
    Const::Fast ->import::into($target);
    List::Util  ->import::into($target, qw(max));
}

1;

Затем в скриптах вы можете сказать use CommonModules;, и все они будут загружены с правильными импортами и рядом других сложных вещей. Он работает для прагм, модулей, классов.

Это пример с голубыми костями. В качестве аргументов можно использовать аргументы типа use CommonModules qw(base ...); и import для управления различными группами пакетов на основе этих аргументов. С этим можно многое сделать. См. Документы и Блог Friedman.