Perl Regex替代,评估环境变量

时间:2018-06-04 15:47:54

标签: regex perl substitution

我试图在评估中使用Perl的正则表达式替换来帮助使一些配置文件在Clearcase期间更具动态性 - > Git迁移。 Clearcase系统高度依赖于/ vob /目录,但是我们需要让它更加动态,让我们的Jenkins构建变得快乐。我试图降低在迁移过程中打破Clearcase构建的可能性。

我有一个配置文件是一个文本文件,每行有一个路径:

/vob/config/file1
/vob/config/file2
/vob/config/file3

此配置会对这些配置文件执行一些其他操作。编排那些"东西"由Perl脚本管理。我希望在运行脚本时可以覆盖一些环境变量(" VOB_FOO")。

我是Perl的新手,所以我认为使用Perl环境变量语法,对它进行正则表达式并在我处理文件时在线评估替换结果。< / p>

我希望我的新配置文件在文件中包含明确的$ ENV {&#39; VOB_FOO&#39;}条目,因此文件将变为:

$ENV{'VOB_FOO'}/config/file1   ->    /home/me/foo/config/file1
$ENV{'VOB_FOO'}/config/file2   ->    /home/me/foo/config/file2
$ENV{'VOB_FOO'}/config/file3   ->    /home/me/foo/config/file3

结果正则表达式替换+评估将变成(如果VOB_FOO = / home / me / foo):

$ENV{'VOB_FOO'}/config/file1   ->    /home/me/foo/config/file1
$ENV{'VOB_FOO'}/config/file2   ->    /home/me/foo/config/file2
$ENV{'VOB_FOO'}/config/file3   ->    /home/me/foo/config/file3

我的正则表达式匹配正常,看起来替换正在起作用,但替换的评估部分不是,我可以在这里使用一些帮助。我得到了一个成功的比赛,但替换结果如下:

$ENV{'VOB_FOO'}/config/file1   ->    $ENV('VOB_FOO'}/config/file1
$ENV{'VOB_FOO'}/config/file2   ->    $ENV('VOB_FOO'}/config/file2
$ENV{'VOB_FOO'}/config/file3   ->    $ENV('VOB_FOO'}/config/file3

对此评估有什么警告或某种方式我可以正常工作吗?这是我的代码:

## See if we need to substitute an environment variable (e.g., is there a $ENV{} anywhere?)
## s - substitute through regular expressions (s/foo/bar/e)
## e modifier evaluates replacement as perl statement

{
    use re 'debugcolor';

    # this is for debugging only - I want to substitute 
    # grab the $ENV('VOB') string from the file and substitute
    # I may have multiple environment variables that I have to 
    # contend with. 
    my $vob = $ENV{'VOB'};  
    print $vob; 
    print "\n";

    my $regexp = qr/(\$ENV\{[\'][\w]*[\']\})/;

    if( $second =~ m/$regexp/ )
    {
        print "Found the regexp; attempting substitution.\n";
        $second =~ s/$regexp/$1/e;  
    }
    else
    {
        print $regexp + "\n";
        print $second + "\n";
        print "Did not find the regexp\n";
    }
}

我也愿意接受批评或提出更好的方法来做到这一点 - 在我努力实现这一目标的过程中,我并没有依赖这种方法或代码。

2 个答案:

答案 0 :(得分:2)

我认为你需要的就是这个。它不是提取整个表达式,而是采用哈希键并在真实%ENV

上使用它

我添加了一个替换,以便可以使用或不使用引号来编写散列键,并且可能具有前导或尾随空格

$second =~ s/\$ENV\{\s*(?|(\w+)|'(\w+)')\s*\}/$ENV{$1}/g

答案 1 :(得分:0)

Since you are capturing a literal string the $1 contains mere characters ('$'.'E'.'N'...), which first need be interpolated into a variable, which can then be evaluated. So, need two evals

use warnings;
use strict;
use feature 'say';

my $var = q(a_$ENV{SHELL}_b);   # like $ENV{'VOB'} read from a file

if ( $var =~ s/(\$ENV\{.*?\})/$1/ee ) {
    say $var
}

Since } isn't ever a part of the environment variable name I simply match everything up to } using the non-greedy .*?. See this post for a detailed explanation of ee.

However, note that ee comes with serious security considerations, as it will turn the given string into a variable and eval it, no questions asked. It also doesn't work in taint mode. So use carefully and only in tightly controlled circumstances.

A safer way is to capture the environment variable name itself and then normally have %ENV of it evaluated in the replacement, as Borodin's answer suggests

$second =~ s/\$ENV(\{(.*?)\}/$ENV{$1}/g;

Either way, also note that you don't need to first match then substitute.


  The danger is really that the string may happen to contain any code, which is blindly eval-ed.