Have perl execute shellscript & take over env vars
I have a shell script that does nothing but set a bunch of environment variables:
export MYROOTDIR=/home/myuser/mytools
export PATH=$MYROOTDIR/bin:$PATH
export MYVERSION=0.4a
I have a perl script, and I want the perl script to somehow get the perl script to operate with the env vars listed in the shell script. I need this to happen from within the perl script though, I do not want the caller of the perlscript to have to manually source the shellscript first.
When trying to run
system("sh myshell开发者_JAVA百科.sh")
the env vars do not "propagate up" to the process running the perl script.
Is there a way to do this?
To answer this question properly, I need to know a bit more.
- Is it okay to actually run the shell script from within the perl script?
- Are the variable assignments all of the form
export VAR=value
(i.e. with fixed assignments, no variable substitutions or command substitutions)? - Does the shell script do anything else but assign variables?
Depending on answers to these, options of different complexity exist.
Thanks for the clarification. Okay, here's how to do it. Other than assigning variables, your script has no side effects. This allows to run the script from within perl. How do we know what variables are exported in the script? We could try to parse the shell script, but that's not the Unix way of using tools that do one thing well and chain them together. Instead we use the shell's export -p
command to have it announce all exported variables and their values. In order to find only the variables actually set by the script, and not all the other noise, the script is started with a clean environment using env -i
, another underestimated POSIX gem.
Putting it all together:
#!/usr/bin/env perl
use strict;
use warnings;
my @cmd = (
"env", "-i", "PATH=$ENV{PATH}", "sh", "-c", ". ./myshell.sh; export -p"
);
open (my $SCRIPT, '-|', @cmd) or die;
while (<$SCRIPT>) {
next unless /^export ([^=]*)=(.*)/;
print "\$ENV{$1} = '$2'\n";
$ENV{$1} = $2;
}
close $SCRIPT;
Notes:
- You need to pass to
env -i
all environment yourmyshell.sh
needs, e.g.PATH
. - Shells will usually export the
PWD
variable; if you don't want this in your perl ENV hash, addnext if $1 eq 'PWD';
after the firstnext
.
This should do the trick. Let me know if it works.
See also:
- http://pubs.opengroup.org/onlinepubs/009695399/utilities/export.html
- http://pubs.opengroup.org/onlinepubs/009695399/utilities/env.html
Try Shell::Source.
You can set the environment variables inside the BEGIN block. BEGIN block is executed before the rest of the code, setting the environment variables in this block makes them visible to the rest of the code before it is compiled and run. If you have any perl modules to 'use' based on the enviornment settings, BEGIN block makes it possible.
Perl uses a special hash %ENV to maintain the environment variables. You can modify the contents of this hash to set the env variables.
EXAMPLE :
BEGIN
{
$ENV { 'MYROOTDIR' } = '/home/myuser/mytools';
$ENV { 'PATH' } = "$ENV{ 'MYROOTDIR' }/bin:$ENV{ 'PATH' }";
}
Wouldn't it be easier for a shell script to set the variables, and then call the perl program?
i.e.:
run.sh:
#!/bin/sh
export MYROOTDIR=/home/myuser/mytools
export PATH=$MYROOTDIR/bin:$PATH
export MYVERSION=0.4a
./program.pl
This can now be done with Env::Modify
with few changes to your existing code.
use Env::Modify 'system';
...
system("sh myshell.sh");
print $ENV{MYROOTDIR}; # "/home/myuser/mytools"
or if all your shell script does is modify the environment, you can use the source
function
use Env::Modify `source`;
source("myshell.sh");
print $ENV{MYVERSION}; # "0.4a"
精彩评论