开发者

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 your myshell.sh needs, e.g. PATH.
  • Shells will usually export the PWD variable; if you don't want this in your perl ENV hash, add next if $1 eq 'PWD'; after the first next.

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"
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜