I have a perl code running on Windows. This code calls open
twice to execute two different batch files. The first one set an environment variable and the second one needs to use it. Unfortunately, the value sets to the variable is lost between the two calls.
Here is my Perl code.
my $hdl;
open($hdl, "set.bat |");
while(my $line = <$hdl>) {
print("$line\n");
}
close($hdl);
open($hdl, "get.bat |");
while(my $line = <$hdl>) {
print("$line\n");
}
close($hdl);
My set.bat
file which sets the environment variable:
set VAR=20
echo %VAR%
And my get.bat
which uses the environment variable:
echo %VAR%
When I run the perl code, here is the results:
>perl my_code.pl
>set VAR=20
>echo 20
20
>echo
ECHO is on.
We can see set.bat
correctly sets the value of VAR
but get.bat
is unable to use it.
Also, if I run my two batch scripts in a row from the cmd
prompt, I have the result I expect:
>set.bat
>set VAR=20
>echo 20
20
>get.bat
>echo 20
20
What can I do to let my second batch script to use my environment variable in my perl code?
The open
with a pipe creates a new process† and then your set.bat
runs in that process and sets that environment variable in that process, which then exits.
Then get.bat
runs in a yet different process and can see nothing of the first process.
However, they both inherit the environment of the process in which your Perl script is running. So you can set the needed environment in the script (via %ENV
for instance) and then create a subprocess, and then that subprocess sees the environment.‡
On the other hand, you can run both shell scripts in the same subprocess, if that fits your purposes, via system
for instance. Then one can export
a variable into the environment, and after it's source
-ed the next script to run will see it. Here is an example in Linux (can't do Windows right now).
A command-line program ("one-liner")
perl -we'system("/bin/bash", "-c", q(source set.bat.sh; get.bat.sh))'
with the file set.bat.sh
#!/bin/bash
VAR=20
export VAR
and file get.bat.sh
#!/bin/bash
echo $VAR
The one-liner prints one line with 20
.
† The pipe-open
is normally said to fork
a process (see open), but on Windows that can only be emulated (via threads) as there is no native fork
; see perlfork. However, perlport indicates that on Windows the
pipe-open
does create a subprocess (via Win32 API).
‡ A Linux example (can't test in Windows right now)
perl -we'$v = qx("set.bat.sh"); chomp $v; $ENV{VAR} = $v; system("get.bat.sh")'
with set.bat.sh
file
#!/bin/bash
VAR=20
echo $VAR
and get.bat.sh
#!/bin/bash
echo $VAR
Since a subprocess cannot directly change the environment of its parent the set.bat.sh
prints $VAR
to STDOUT
and then its parent, the perl script, can read it from that stream (captured by qx
) and set it in its own environment, which its next (grand-)child get.bat.sh
inherits. (A system
forks a process, and in it another one is forked to run get.bat.sh
. Environment is passed down.)
The weakness of this, of course, is that the perl script needs to know the name of the variable, VAR
. An improvement then would be for the set.bat
to send the name itself along with the value.
That's not easily done. The reason is, that a child process normally inherits a copy of the parents process environment. Including environment variables.
See: How to Share ENV Variables Among Perl Scripts
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With