与版本相关的后备代码

时间:2015-06-15 18:02:42

标签: perl

我有一个需要在多个服务器上运行的脚本,但是,每个服务器可能没有相同版本的Perl可用,并且可能具有不同的功能。

Perl v5.14引入了/r modifier for regular expressions,它返回替换结果并单独保留原始文本。如果没有,我想改用一些后备代码。

以下是一个例子:

#!/usr/bin/perl

# Don't use cryptic variable names
use English;

my $str = "Hello, World!";
my $search = ',';

if ($PERL_VERSION ge v5.14) {
    print "Using version that supports /r modifier\n";

    # Perl v5.14 introduced the /r flag for regular expressions
    # From the perldoc: r  - perform non-destructive substitution and return the new value
    print "After replacement: " . ($str =~ s/\Q${search}\E/_/gr) . $/;
    print "Original string: " . $str . $/;

} else {
    print "This version does not support the /r modifier\n";

    # Prior to Perl v5.14, no /r option existed and the original string will be clobbered
    # To deal with this, we need to make a copy first, then modify the copy instead
    my $str_copy = $str;
    $str_copy =~ s/\Q${search}\E/_/g;

    print "After replacement: " . $str_copy . $/;
    print "Original string: " . $str . $/;
}

当Perl v5.14可用时,运行脚本会得到所需的结果:

$ ./version_dependent.pl
Using version that supports /r modifier
After replacement: Hello_ World!
Original string: Hello, World!

当使用小于v5.14的版本时,由于r我收到语法错误:

$ ./version_dependent.pl
Bareword found where operator expected at ./version_dependent.pl line 15, near "s/\Q${search}\E/_/gr"
syntax error at ./version_dependent.pl line 15, near "s/\Q${search}\E/_/gr"
Execution of ./version_dependent.pl aborted due to compilation errors.

我想得到的是:

$ ./version_dependent.pl
This version does not support the /r modifier
After replacement: Hello_ World!
Original string: Hello, World!

有没有办法让脚本按预期运行?
如果这是一个类C语言,我使用预处理器处理问题,但我不认为Perl具有该功能。

修改:上面的代码只是一个示例 在实际应用中,由于性能原因,我在5.14中使用了一些功能。我可以在小于5.14的版本中手动重新创建功能,但性能会受到影响。

2 个答案:

答案 0 :(得分:3)

许多最近的功能都不是向前兼容的。正如您所见,使用对于您运行的perl版本而言过于新的功能,您将获得编译时错误。使用块 - class MissionResource(ModelResource): text_mission = fields.ToOneField('path.to.TextMissionResource', attribute='text_mission', related_name='mission', full = True, null = True) class TextMissionResource(ModelResource): mission = fields.ToOneField(MissionResource, attribute='mission', related_name='text_mission') 将无济于事,因为块的内容需要对当前的perl解释器有效。

您正在检查当前的perl版本和分支。 $] variable是这样做的一种机制。检查eval(在$Config{PERL_VERSION}之后)是另一个。

ThisSuitIsBlack没有向你指出use Config编译指示,即

if

根据当前perl的功能加载不同的模块。在运行时,条件use if $] >= 5.014, 'Foo::New'; # take advantage of latest syntax,features use if $] <= 5.014, 'Foo::Old'; # workarounds for missing features 语句可以以相同的方式工作

require

最后,对于依赖于版本的代码,块eval不是一种可行的技术,但字符串eval是。要点是:

if ($] >= 5.014) {
    require Foo::New;
} else {
    require Foo::Old;
}

See the Test::Builder module真实地使用这种结构。

答案 1 :(得分:1)

eval的字符串形式包装它(因为eval的块形式会导致同样的错误):

#!/usr/bin/perl

# Don't use cryptic variable names
use English;

my $str = "Hello, World!";
my $search = ',';

if ($PERL_VERSION ge v5.14) {
    print "Using version that supports /r modifier\n";

    # Perl v5.14 introduced the /r flag for regular expressions
    # From the perldoc: r  - perform non-destructive substitution and return the new value
    eval 'print "After replacement: " . ($str =~ s/\Q${search}\E/_/gr) . $/;';
    print "Original string: " . $str . $/;

} else {
    print "This version does not support the /r modifier\n";

    # Prior to Perl v5.14, no /r option existed and the original string will be clobbered
    # To deal with this, we need to make a copy first, then modify the copy instead
    my $str_copy = $str;
    $str_copy =~ s/\Q${search}\E/_/g;

    print "After replacement: " . $str_copy . $/;
    print "Original string: " . $str . $/;
}