system (. env.sh) [dot space env.sh] , however wont work. Child" />
开发者

how to source a shell script [environment variables] in perl script without forking a subshell?

I want to call "env.sh " from "my_perl.pl" without forking a subshell. I tried with ba开发者_JAVA技巧cktics and system like this --> system (. env.sh) [dot space env.sh] , however wont work.


Child environments cannot change parent environments. Your best bet is to parse env.sh from inside the Perl code and set the variables in %ENV:

#!/usr/bin/perl

use strict;
use warnings;

sub source {
    my $name = shift;

    open my $fh, "<", $name
        or die "could not open $name: $!";

    while (<$fh>) {
        chomp;
        my ($k, $v) = split /=/, $_, 2;
        $v =~ s/^(['"])(.*)\1/$2/; #' fix highlighter
        $v =~ s/\$([a-zA-Z]\w*)/$ENV{$1}/g;
        $v =~ s/`(.*?)`/`$1`/ge; #dangerous
        $ENV{$k} = $v;
    }
}

source "env.sh";

for my $k (qw/foo bar baz quux/) {
    print "$k => $ENV{$k}\n";
}

Given

foo=5
bar=10
baz="$foo$bar"
quux=`date +%Y%m%d`

it prints

foo => 5
bar => 10
baz => 510
quux => 20110726

The code can only handle simple files (for instance, it doesn't handle if statements or foo=$(date)). If you need something more complex, then writing a wrapper for your Perl script that sources env.sh first is the right way to go (it is also probably the right way to go in the first place).

Another reason to source env.sh before executing the Perl script is that setting the environment variables in Perl may happen too late for modules that are expecting to see them.

In the file foo:

#!/bin/bash

source env.sh

exec foo.real

where foo.real is your Perl script.


You can use arbitrarily complex shell scripts by executing them with the relevant shell, dumping their environment to standard output in the same process, and parsing that in perl. Feeding the output into something other than %ENV or filtering for specific values of interest is prudent so you don't change things like PATH that may have interesting side effects elsewhere. I've discarded standard output and error from the spawned shell script although they could be redirected to temporary files and used for diagnostic output in the perl script.

foo.pl:

#!/usr/bin/perl
open SOURCE, "bash -c '. foo.sh >& /dev/null; env'|" or
die "Can't fork: $!";

while(<SOURCE>) {
if (/^(BAR|BAZ)=(.*)/) {
    $ENV{$1} = ${2} ;
}
}

close SOURCE;

print $ENV{'BAR'} . "\n";

foo.sh: export BAR=baz


Try this (unix code sample):

cd /tmp

vi s

#!/bin/bash
export blah=test

vi t

#!/usr/bin/perl

if ($ARGV[0]) {
    print "ENV second call is : $ENV{blah}\n";
} else {
    print "ENV first call is : $ENV{blah}\n";
    exec(". /tmp/s; /tmp/t 1");
}

chmod 777 s t

./t

ENV first call is :

ENV second call is : test

The trick is using the exec to source your bash script first and then calling your perl script again with an argument so u know that you are being called for a second time.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜