Perl 正则表达式替换,环境变量评估

Posted

技术标签:

【中文标题】Perl 正则表达式替换,环境变量评估【英文标题】:Perl Regex Substitution, Evaluation of Environment Variables 【发布时间】:2018-06-04 15:47:54 【问题描述】:

我正在尝试使用 Perl 的正则表达式替换和评估来帮助在 Clearcase -> Git 迁移期间使一些配置文件更加动态。 Clearcase 系统高度依赖于 /vob/ 目录,但我们需要使其更加动态,以使我们的 Jenkins 构建更快乐。我正在尝试减少在迁移时破坏 Clearcase 构建的可能性。

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

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

这个配置对那些配置文件做了一些额外的事情。这些“东西”的编排由 Perl 脚本管理。我想要一些环境变量(“VOB_FOO”),我可以在运行脚本时覆盖它们。

我是 Perl 的新手,所以我的想法是使用 Perl 环境变量语法,对其执行正则表达式并在处理文件时在线评估替换结果。

我希望我的新配置文件在文件中有明确的 $ENV'VOB_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

而生成的正则表达式替换+求值将变成 (if 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";
    

我也愿意就更好的方法提出批评或建议 - 在我努力实现这一目标时,我不受这种方法或代码的束缚。

【问题讨论】:

更改 $second =~ s/$regexp/$1/e;到 $second =~ s/$regexp/$vob/e; @Andrey - 我希望我的正则表达式找到任何环境变量字符串并替换它(我最初并没有说清楚)。我将要处理多个变量,并且我不想将每个变量的逻辑构建到代码中。您给了我以不同方式处理此问题的想法 - 查找 /vob/,查看是否设置了 VOB_FOO 环境变量,如果两者都为真,则进行替换。 你能更详细地解释一下你的输入是什么样的吗?我不太明白这些环境变量在哪里。您的输入文件中有文字 $ENV... 字符串吗?或者是脚本运行的环境的那些部分?或两者?请edit 并添加更多详细信息。 注意$regexp + "\n"等应该是$regexp . "\n" 谢谢@Borodin!昨天在 Python、Groovy 和 Perl 之间跳来跳去,结果搞砸了。 【参考方案1】:

我想你只需要这个。它没有提取整个表达式,而是采用哈希键并将其用于真实的%ENV

我添加了一个替代项,以便散列键可以带引号或不带引号,并且可以有前导或尾随空格

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

【讨论】:

我喜欢这个解决方案——它对我有用,而且非常优雅。我确实修改了我的方法,以便提取哈希键,作为我最终解决方案的基础。我会接受这个作为答案。【参考方案2】:

使用捕获的文字字符串,$1 仅包含字符 ('$'.'E'.'N'...),首先需要将其制成变量名称,然后才能对其进行评估。所以,需要两个评估

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

my $var = q(a_$ENVSHELL_b);   # like $ENV'VOB' read from a file

if ( $var =~ s/(\$ENV\.*?\)/$1/ee )   # WARNING: security?
    say $var

由于 从来都不是环境变量名称的一部分,所以我只需使用非贪婪的.*? 匹配直到 的所有内容。 ee的详细解释见this post。

但是,请注意ee 带有严重的安全考虑,因为它会将给定的字符串转换为变量 和eval 它,没有问题。它在污点模式下也不起作用。因此,请谨慎使用,并且只能在严格控制的情况下使用。

更安全的方法是捕获环境变量名称本身,然后通常在替换中评估它的 %ENV,正如 Borodin's answer 建议的那样

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

无论哪种方式,还请注意,您不需要先匹配然后替换。


危险在于,如果字符串恰好包含任何代码,它就会盲目地eval-ed

【讨论】:

感谢您的解释和替代方案。我在用户提供的代码上看到了多篇关于 eval(和 double-eval)安全问题的帖子。由于运行它的输入文件是受控资源,因此我不太担心,但有安全意识总是一件好事! 对,您的问题清楚地表明该资源是安全的,否则我不会提到/ee。然而,代码趋于发展,一般来说,这个特性应该是一个很好的警告。请注意,/e 没有任何类似的安全含义,因为解析器永远不会参与其中。它只是评估源文件中的代码。

以上是关于Perl 正则表达式替换,环境变量评估的主要内容,如果未能解决你的问题,请参考以下文章

在 Perl 正则表达式中展开环境变量

Perl正则表达式引用

Perl编程-6正则表达式--替换+转化

sed 和 Perl 正则表达式替换一次,带有多个替换标志

如何在 perl 正则表达式替换命令中使用 unicode 字符?

正则表达式中的 perl 正则表达式