我希望能够在不派生子shell的情况下从"my_perl.pl"中调用"env.sh"。我尝试使用反引号和system命令,像这样——>
system (. env.sh)
【点空格env.sh】,但是无法正常工作。子环境无法更改父环境。您最好的选择是从Perl代码内部解析env.sh
,并在%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";
}
给定
foo=5
bar=10
baz="$foo$bar"
quux=`date +%Y%m%d`
它会打印输出foo => 5
bar => 10
baz => 510
quux => 20110726
该代码只能处理简单的文件(例如,它不能处理if
语句或foo=$(date)
)。如果您需要更复杂的东西,则编写一个用于源化env.sh
的Perl脚本包装器是正确的做法(这也可能是一开始就正确的做法)。
在执行Perl脚本之前,另一个源化env.sh
的原因是在Perl中设置环境变量可能发生得太晚,以至于期望看到它们的模块无法找到这些变量。
在文件foo
中:
#!/bin/bash
source env.sh
exec foo.real
其中foo.real是您的Perl脚本。
#!/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: 导出 BAR=baz
尝试以下UNIX代码示例:
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"翻译为中文是:修改s和t文件的权限为777。
执行"./t"命令。
"ENV first call is :"翻译为中文是:"第一次调用ENV的结果为:"。
"ENV second call is : test"翻译为中文是:"第二次调用ENV的结果为:test"。
技巧在于使用exec先执行你的bash脚本,然后再用一个参数调用你的perl脚本,这样你就知道自己被第二次调用了。