让perl执行shellscript&;接管环境变量

让perl执行shellscript&;接管环境变量,perl,Perl,我有一个shell脚本,它除了设置一组环境变量外什么都不做: export MYROOTDIR=/home/myuser/mytools export PATH=$MYROOTDIR/bin:$PATH export MYVERSION=0.4a 我有一个perl脚本,我希望perl脚本以某种方式让perl脚本与shell脚本中列出的env vars一起运行。不过,我需要在perl脚本中实现这一点,我不希望perlscript的调用方必须首先手动获取shellscript的源代码 当你想跑的时

我有一个shell脚本,它除了设置一组环境变量外什么都不做:

export MYROOTDIR=/home/myuser/mytools
export PATH=$MYROOTDIR/bin:$PATH
export MYVERSION=0.4a
我有一个perl脚本,我希望perl脚本以某种方式让perl脚本与shell脚本中列出的env vars一起运行。不过,我需要在perl脚本中实现这一点,我不希望perlscript的调用方必须首先手动获取shellscript的源代码

当你想跑的时候

system("sh myshell.sh")
env变量不会“向上传播”到运行perl脚本的进程


有办法吗?

要正确回答这个问题,我需要知道更多

  • 从perl脚本中实际运行shell脚本可以吗
  • 变量赋值是否全部采用
    export VAR=value
    的形式(即采用固定赋值,无变量替换或命令替换)
  • shell脚本除了分配变量外,还做其他事情吗
根据这些问题的答案,存在不同复杂性的选项

谢谢你的澄清。好的,这是怎么做的。除了分配变量,脚本没有任何副作用。这允许从perl中运行脚本。我们如何知道脚本中导出了哪些变量?我们可以尝试解析shell脚本,但这不是Unix使用工具的方式,这些工具可以很好地完成一件事并将它们链接在一起。相反,我们使用shell的
export-p
命令让它宣布所有导出的变量及其值。为了只找到脚本实际设置的变量,而不是所有其他噪声,脚本使用
env-i
(另一个被低估的POSIX gem)在干净的环境中启动

总而言之:

#!/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;
#/usr/bin/env perl
严格使用;
使用警告;
my@cmd=(
“env”、“-i”、“PATH=$env{PATH}”、“sh”、“-c”、“./myshell.sh;导出-p”
);
打开(我的$SCRIPT,'-|',@cmd)或死亡;
而(){
下一步除非/^导出([^=]*)=(.*)/;
打印“\$ENV{$1}='$2'\n”;
$ENV{$1}=$2;
}
关闭$SCRIPT;
注:

  • 您需要传递到
    env-i
    您的
    myshell.sh
    所需的所有环境,例如
    PATH
  • Shell通常会导出
    PWD
    变量;如果您不想在perl ENV散列中使用它,请在$1 eq'PWD'中添加
    next在第一个
    下一个
    之后
这应该能奏效。让我知道它是否有效

另见:


您可以在BEGIN块内设置环境变量。 BEGIN块在代码的其余部分之前执行,在该块中设置环境变量使其在编译和运行之前对代码的其余部分可见。 如果您有任何基于环境设置“使用”的perl模块,BEGIN块使之成为可能

Perl使用一个特殊的哈希%ENV来维护环境变量。 您可以修改此哈希的内容以设置环境变量

例如:

BEGIN 
{
    $ENV { 'MYROOTDIR' } = '/home/myuser/mytools';
    $ENV { 'PATH' } = "$ENV{ 'MYROOTDIR' }/bin:$ENV{ 'PATH' }";
}

试试。

shell脚本设置变量,然后调用perl程序不是更容易吗

i、 e:

run.sh:

#!/bin/sh

export MYROOTDIR=/home/myuser/mytools
export PATH=$MYROOTDIR/bin:$PATH
export MYVERSION=0.4a

./program.pl
现在只需对现有代码进行少量更改即可完成此操作

use Env::Modify 'system';
...
system("sh myshell.sh");
print $ENV{MYROOTDIR};      # "/home/myuser/mytools"
或者,如果您的shell脚本所做的只是修改环境,那么您可以使用
source
函数

use Env::Modify `source`;
source("myshell.sh");
print $ENV{MYVERSION};      # "0.4a"

谢谢@Jens-非常有帮助。我正在处理的perl脚本只需要设置少量的env变量,这是复杂的、遗留的、340行ksh脚本的结果;这不是我想要移植到perl的东西。虽然这肯定是一种一次性解决问题的方法,但它不会自动获取对shell脚本所做的更改(我的解决方案就是这样做的)。对于较大的脚本来说,这可能是一项艰巨的任务(如果shell脚本使用if/else/while/for等控制结构和其他奇特的shell功能,这几乎是不可能的——是的,我知道,最初的问题说它没有。)