how to source a shell script [environment variable

2020-03-15 02:19发布

I want to call "env.sh " from "my_perl.pl" without forking a subshell. I tried with backtics and system like this --> system (. env.sh) [dot space env.sh] , however wont work.

标签: perl shell
3条回答
不美不萌又怎样
2楼-- · 2020-03-15 03:00

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.

查看更多
狗以群分
3楼-- · 2020-03-15 03:08

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

查看更多
甜甜的少女心
4楼-- · 2020-03-15 03:09

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.

查看更多
登录 后发表回答