【问题标题】:Odd perl foreach behavior using pattern matching使用模式匹配的奇怪 perl foreach 行为
【发布时间】:2013-09-16 00:44:14
【问题描述】:

我正在编写一个 perl 脚本,它将查看 Oracle 11g 数据库警报日志并报告错误。我遇到问题的代码如下:

if ($_ =~ (m/WARNING/ or m/ORA/)){print $_ . "\n";}

我希望 if 语句(第 31 行)产生:

Mon Sep 01 01:01:01 1111 WARNING: THIS IS AN ERROR MESSAGE
Mon Sep 04 04:04:04 4444 WARNING: THIS IS ANOTHER ERROR MESSAGE
Mon Sep 05 05:05:05 5555 ORA-123456 HAS OCCURRED.
Mon Sep 06 06:06:06 6666 WARNING MESSAGE!

但是它正在生产:

Mon Sep 01 01:01:01 1111 WARNING: THIS IS AN ERROR MESSAGE
Mon Sep 02 02:02:02 2222 log switch has occurred
Mon Sep 03 03:03:03 3333 AUDIT: Purge complete
Mon Sep 05 05:05:05 5555 ORA-123456 HAS OCCURRED.

如果我为每个模式使用单独的 if 语句,我会得到想要的结果:

if ($_ =~ (m/WARNING/)){print $_ . "\n";}
if ($_ =~ (m/ORA/)){print $_ . "\n";}

我不知道为什么会这样。

数据

Mon Sep 01 01:01:01 1111
WARNING: THIS
IS
AN
ERROR
MESSAGE
Mon Sep 02 02:02:02 2222
log switch
has
occurred
Mon Sep 03 03:03:03 3333
AUDIT: Purge complete
Mon Sep 04 04:04:04 4444
WARNING: THIS
IS
ANOTHER
ERROR
MESSAGE
Mon Sep 05 05:05:05 5555
ORA-123456 HAS
OCCURRED.
Mon Sep 06 06:06:06 6666
WARNING
MESSAGE!

脚本

use strict;
use warnings;

my $input = $ARGV[0];
my $output = 'output.out';
my $log_line;
my @log_entries;

open INPUT, $input or die "Could not open $input: $!";
while(<INPUT>)
{
    chomp;
    if ($_ =~ m/^\w{3} \w{3} \d{2} \d{2}:\d{2}:\d{2} \d{4}/)
    {
        {
            push (@log_entries, $log_line);
        }
        $log_line = "$_ ";
    }
    else
    {
        $log_line .= "$_ ";
    }
}
push (@log_entries, $log_line);
close (INPUT);

foreach (@log_entries)
{
    next if not defined($_);
    if ($_ =~ (m/WARNING/ or m/ORA/)){print $_ . "\n";} #No idea why this doesn't work
#   if ($_ =~ (m/WARNING/)){print $_ . "\n";}
#   if ($_ =~ (m/ORA/)){print $_ . "\n";}
}

【问题讨论】:

  • 我不知道 Perl 有 OR 运算符....?!
  • @Simon Catlin,or 的行为与|| 一样。不同之处在于or 的优先级远低于||or 通常用于流量控制(例如open(...) or die $!)。运算符记录在perlop

标签: regex arrays oracle perl


【解决方案1】:

缺少绑定运算符(=~!~),

m/.../

意思

$_ =~ m/.../

也就是说

$_ =~ (m/WARNING/ or m/ORA/)

意思

$_ =~ ($_ =~ m/WARNING/ or $_ =~ m/ORA/)

所以你最终会这样做

$_ =~ ''

$_ =~ '1'

这显然不是你想要的。请改用以下方法之一:

$_ =~ m/WARNING/ or $_ =~ m/ORA/
   -or-
/WARNING/ || /ORA/
   -or-
/WARNING|ORA/

【讨论】:

  • 谢谢,很好的回答。我真的很挣扎。这就解释了为什么我必须输入:next if not defined($_);我一直在串联 (.) 或字符串中使用未初始化的值 $_
【解决方案2】:

这就是你如何使用 or 操作将这两行组合在一起。

if ($_ =~ (m/(WARNING|ORA)/)){print $_ . "\n";}

【讨论】:

    【解决方案3】:

    您必须在匹配结果上定义布尔表达式而不是匹配运算符 - 使用

    if (($_ =~ m/WARNING/) or ($_ =~ m/ORA/)) {print $_ . "\n";}
    

    而不是

    if ($_ =~ (m/WARNING/ or m/ORA/)){print $_ . "\n";}
    

    【讨论】:

      猜你喜欢
      • 2011-12-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-27
      • 2016-01-03
      • 2011-06-25
      相关资源
      最近更新 更多