【问题标题】:Have perl execute shellscript & take over env vars让 perl 执行 shellscript 并接管环境变量
【发布时间】:2017-06-23 22:05:46
【问题描述】:

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

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

我有一个 perl 脚本,我希望 perl 脚本以某种方式让 perl 脚本与 shell 脚本中列出的环境变量一起操作。虽然我需要在 perl 脚本中发生这种情况,但我不希望 perlscript 的调用者必须首先手动获取 shellscript。

尝试运行时

system("sh myshell.sh")

环境变量不会“向上传播”到运行 perl 脚本的进程。

有没有办法做到这一点?

【问题讨论】:

    标签: perl


    【解决方案1】:

    要正确回答这个问题,我需要了解更多。

    • 可以从 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;
    

    注意事项:

    • 您需要将myshell.sh 需要的所有环境传递给env -i,例如PATH
    • Shell 通常会导出PWD 变量;如果您不希望在您的 perl ENV 哈希中使用它,请在第一个 next 之后添加 next if $1 eq 'PWD';

    这应该可以解决问题。让我知道它是否有效。

    另见:

    【讨论】:

    • 感谢@Jens - 非常有帮助。由于复杂的、遗留的、340 行的 ksh 脚本,我正在处理的 perl 脚本只需要少数几个环境变量集;不是我想移植到 perl 的东西。
    【解决方案2】:

    试试Shell::Source

    【讨论】:

      【解决方案3】:

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

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

      示例:

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

      【讨论】:

      • 虽然这肯定是一次解决问题的方法,但它不会自动获取对 shell 脚本所做的更改(我的解决方案就是这样做的)。对于大型脚本来说,这可能是一项艰巨的任务(如果 shell 脚本使用 if/else/while/for 等控制结构和其他花哨的 shell 功能,那几乎是不可能的——是的,我知道,最初的问题说它没有。 )
      【解决方案4】:

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

      即:

      运行.sh:

      #!/bin/sh
      
      export MYROOTDIR=/home/myuser/mytools
      export PATH=$MYROOTDIR/bin:$PATH
      export MYVERSION=0.4a
      
      ./program.pl
      

      【讨论】:

        【解决方案5】:

        现在可以使用 Env::Modify 完成此操作,只需对现有代码进行少量更改。

        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"
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-12-03
          • 1970-01-01
          • 2021-06-17
          • 2012-08-02
          • 1970-01-01
          • 2023-03-24
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多