【问题标题】:how to source a shell script [environment variables] in perl script without forking a subshell?如何在不分叉子shell的情况下在perl脚本中获取shell脚本[环境变量]?
【发布时间】:2011-10-13 08:07:01
【问题描述】:

我想从“my_perl.pl”调用“env.sh”而不用分叉子shell。我尝试过使用 backtics 和这样的系统 --> system (. env.sh) [dot space env.sh] ,但是不起作用。

【问题讨论】:

    标签: perl shell


    【解决方案1】:

    试试这个(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 脚本,这样你就知道你被第二次调用了。

    【讨论】:

      【解决方案2】:

      您可以使用任意复杂的 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

      【讨论】:

      • 只有在 shell 脚本故意导出变量时才使用“env”。如果脚本没有专门导出它们,请尝试使用“set”而不是“env”。
      【解决方案3】:

      子环境不能更改父环境。最好的办法是从 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 脚本。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-01-09
        • 2015-01-03
        • 1970-01-01
        • 2023-04-01
        • 2013-09-16
        • 2013-09-04
        • 2010-11-30
        相关资源
        最近更新 更多