检测子进程环境变量发生变化

时间:2013-04-13 02:03:13

标签: perl environment-variables system-calls

我正在运行Perl的动态系统命令列表。有时,这些命令是对环境变量进行(时间/进程内)修改的脚本。例如,考虑这个简单的脚本(目前针对Windows制作):

Script-A-pl:

use strict;
use warnings;
use feature ':5.16';

$ENV{NEW_VAR} = 'this is new var';
say "Script-A.pl can read the new var: ", `echo %NEW_VAR%`;

Output: Script-A.pl can read the new var: this is new var

现在想象一下,从Parent.pl开始,我需要调用Script-A.pl和更晚的Script-B.pl,这取决于环境变量NEW_VAR。所以这就是它们的执行方式:

Parent.pl:

use strict;
use warnings;
use feature ':5.16';

my @commands = ('perl Script-A.pl', 'perl Script-B.pl');

for my $i (@commands) {
    system($i);
}

除了Script-A.pl无法看到Script-B.pl所造成的环境变量发生变化外,其他情况有效。

我已经尝试了不同的方法来调用脚本,即使IPC :: Open3打开一个shell并逐个运行命令列表,但这也无效。

我是否可以通过Parent.pl将这些更改显示给后续系统调用?

感谢您的评论!

旧金山

1 个答案:

答案 0 :(得分:0)

%ENV表示Perl脚本的系统环境,而不是永久系统环境。对它所做的更改仅适用于脚本的进程(以及任何子进程)。由于您使用system调用所有脚本,因此每个脚本的更改仅在该脚本的持续时间内保持最后一次。

要解决此问题,请尝试在同一进程中运行所有Perl脚本,而不是在不同的进程中运行。

my @commands = ('Script-A.pl', 'Script-B.pl', 'echo "some other command"');

for my $cmd (@commands) {
    if ($cmd =~ /\.pl$/)
    {
        do $cmd;
    }
    else
    {
        system($cmd);
    }
}

do <FILE>是一种简单的方法,可以包含来自另一个Perl脚本的代码并运行它。它确保您的所有脚本都在同一个进程中,因此对%ENV的更改将在整个主脚本中保留。

do <FILE>为每个文件提供了一个单独的词法变量空间,因此您不必担心在文件之间发生my冲突而声明的变量。但是,它们共享相同的全局变量空间,因此脚本可能表现不佳(例如,设置一个特殊变量,如$/而不使用local)来破坏行为以这种方式运行时的其他脚本。使用此方法时,您需要检查一切正常。

另一个问题是,上面的代码假定Perl脚本没有参数。如果他们有参数,那就不行。你可以解决这个问题:

my @commands = ('Script-A.pl arg1 arg2');

for my $cmd (@commands) {
    if ($cmd =~ /\.pl\b\s*(.*)$/)
    {
        local @ARGV = split ' ', $1;
        do $cmd;
    }
    else
    {
        system($cmd);
    }
}

为每个脚本提供@ARGV的本地副本,使其看起来像是使用参数调用。此代码仅适用于简单参数(无空格,无shell魔法)。