如何在两次调用之间保持环境变量处于打开状态?



我有一个在Windows上运行的perl代码。此代码调用open两次以执行两个不同的批处理文件。第一个设置一个环境变量,第二个需要使用它。遗憾的是,设置为变量的值在两次调用之间丢失。

这是我的Perl代码。

my $hdl;
open($hdl, "set.bat |");
while(my $line = <$hdl>) {
print("$linen");
}
close($hdl);
open($hdl, "get.bat |");
while(my $line = <$hdl>) {
print("$linen");
}
close($hdl);

我的set.bat设置环境变量的文件:

set VAR=20
echo %VAR%

还有我的get.bat使用环境变量:

echo %VAR%

当我运行perl代码时,结果如下:

>perl my_code.pl
>set VAR=20
>echo 20
20
>echo
ECHO is on.

我们可以看到set.bat正确设置了VAR的值,但get.bat无法使用它。


此外,如果我从cmd提示符连续运行两个批处理脚本,我会得到我期望的结果:

>set.bat
>set VAR=20
>echo 20
20
>get.bat
>echo 20
20

我该怎么做才能让我的第二个批处理脚本在我的 perl 代码中使用我的环境变量?

带有管道的open创建一个新进程然后您的set.bat在该进程中运行并在该进程中设置该环境变量,然后退出。

然后get.bat在一个不同的进程中运行,看不到第一个进程。

但是,它们都继承了运行 Perl 脚本的进程的环境。因此,您可以在脚本中设置所需的环境(例如通过%ENV(,然后创建一个子流程,然后该子流程查看环境。

另一方面,您可以在同一子进程中运行两个 shell 脚本,如果这符合您的目的,例如通过system。然后可以将变量export到环境中,在它source-ed 之后,下一个要运行的脚本将看到它。这是Linux中的一个例子(现在不能做Windows(。

命令行程序("单行"(

perl -we'system("/bin/bash", "-c", q(source set.bat.sh; get.bat.sh))'

与文件set.bat.sh

#!/bin/bash
VAR=20
export VAR

和文件get.bat.sh

#!/bin/bash
echo $VAR

单行打印一行带有20.


管道open通常被称为fork进程(参见打开(,但在Windows上只能模拟(通过线程(,因为没有本机fork;参见perlfork。但是,perlport 表示在 Windows 上 管道 -open确实创建了一个子进程(通过 Win32 API(。


一个Linux示例(目前无法在Windows中测试(

perl -we'$v = qx("set.bat.sh"); chomp $v; $ENV{VAR} = $v; system("get.bat.sh")'

set.bat.sh文件

#!/bin/bash
VAR=20
echo $VAR

get.bat.sh

#!/bin/bash
echo $VAR

由于子进程不能直接更改其父进程的环境,因此set.bat.sh$VAR打印到STDOUT,然后其父进程perl脚本可以从该流(由qx捕获(中读取它并将其设置在自己的环境中,其下一个(孙(子get.bat.sh继承。 (一个system分叉一个进程,其中另一个进程被分叉以运行get.bat.sh。环境是向下传递的。

当然,这样做的弱点是perl脚本需要知道变量的名称,VAR。 然后,改进是让set.bat将名称本身与值一起发送。

这并不容易做到。 原因是,子进程通常继承父进程环境的副本。包括环境变量。

请参阅:如何在Perl脚本之间共享ENV变量

子进程彼此隔离,通常不能影响彼此或父进程的环境。

对于这个有限的示例,也许在Perl中重新实现部分CMD语言就足够了。如果你只需要支持一个小的子集,比如说,将静态字符串分配给变量,这并不难:

if ($line ~ /^sets+(w+)=(w+)$/) {
$ENV{$1} = $2;
}

如果您不是绝对需要将这些值传播到环境中,则可以使用与ENV不同的哈希。

最新更新