【发布时间】:2011-10-13 08:07:01
【问题描述】:
我想从“my_perl.pl”调用“env.sh”而不用分叉子shell。我尝试过使用 backtics 和这样的系统 --> system (. env.sh) [dot space env.sh] ,但是不起作用。
【问题讨论】:
我想从“my_perl.pl”调用“env.sh”而不用分叉子shell。我尝试过使用 backtics 和这样的系统 --> system (. env.sh) [dot space env.sh] ,但是不起作用。
【问题讨论】:
试试这个(unix 代码示例):
cd /tmp
可见
#!/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 第一次调用是:
ENV 第二次调用是:测试
诀窍是首先使用 exec 获取 bash 脚本的源代码,然后使用参数再次调用 perl 脚本,这样你就知道你被第二次调用了。
【讨论】:
您可以使用任意复杂的 shell 脚本,方法是使用相关的 shell 执行它们,将它们的环境转储到同一进程中的标准输出,然后在 perl 中进行解析。将输出馈送到 %ENV 以外的其他内容或过滤特定的感兴趣值是谨慎的做法,因此您不要更改可能在其他地方产生有趣副作用的 PATH 之类的内容。尽管可以将它们重定向到临时文件并用于 perl 脚本中的诊断输出,但我已经从生成的 shell 脚本中丢弃了标准输出和错误。
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: 导出 BAR=baz
【讨论】:
子环境不能更改父环境。最好的办法是从 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))。如果你需要更复杂的东西,那么为你的 Perl 脚本编写一个包装器,首先是 env.sh 是正确的方法(这也可能是正确的方法)。
在执行 Perl 脚本之前获取 env.sh 的另一个原因是,在 Perl 中设置环境变量对于期望看到它们的模块来说可能为时已晚。
在文件foo:
#!/bin/bash
source env.sh
exec foo.real
其中 foo.real 是您的 Perl 脚本。
【讨论】: