【问题标题】:Need to print the last occurrence of a string in Perl需要在 Perl 中打印最后一次出现的字符串
【发布时间】:2011-03-28 16:16:37
【问题描述】:

我在 Perl 中有一个脚本,用于搜索配置文件中的错误,但它会打印出任何出现的错误。我需要匹配配置文件中的内容并仅在上次发生错误时打印出来。有什么想法吗?


哇...我没想到会有这么多回应。我应该更清楚地说明这是用于向 Nagios 发送警报的 Windows 框上的日志监控。这实际上是我的第一个 Perl 程序,所有这些信息都非常有帮助。有谁知道我如何在 wintel 盒子上应用这个任何尾部答案?

【问题讨论】:

  • 到目前为止你写了什么?
  • 最简单的方法,使用tail。例如perl my_perl_script_that_prints_out_errors.pl |尾巴 -1

标签: perl perl-io


【解决方案1】:

大纲:

my $errinfo;
while (<>)
{
    $errinfo = "whatever" if (m/the error pattern/);
}
print "error: $errinfo\n" if ($errinfo);

这会捕获所有错误,但直到最后才打印出来,只有最后一个存在。

【讨论】:

    【解决方案2】:

    另一种方法:

    perl -n -e '$e = $1 if /(REGEX_HERE)/;  END{ print $e }' CONFIG_FILE_HERE
    

    【讨论】:

    • 只是一个小注释:要存储整行,请使用 $_ 而不是 $1 ,或者使用 $. 存储匹配模式的行号。很好的答案,我自己多次使用这种方法
    【解决方案3】:

    您究竟需要打印什么?包含错误的行?比这更多的上下文? File::ReadBackwards 可能会有所帮助。

    【讨论】:

      【解决方案4】:

      蛮力方法涉及通过将STDOUT 指向tail 来设置您自己的管道。这允许您打印所有错误,然后由tail 担心只显示最后一个错误。

      你没有指定,所以我假设一个合法的配置行是这样的

      Name = some value
      

      直接匹配:

      • ^(从行首开始)
      • \w+(一个或多个“单词字符”)
      • \s+(后跟强制空格)
      • =(后跟等号)
      • \s+(更多强制空格)
      • .+(一些强制值)
      • $(在行尾结束)

      把它粘在一起,我们得到

      #! /usr/bin/perl
      
      use warnings;
      use strict;
      
      # for demo only
      *ARGV = *DATA;
      
      my $pid = open STDOUT, "|-", "tail", "-1" or die "$0: open: $!";
      while (<>) {
        print unless /^ \w+ \s+ = \s+ .+ $/x;
      }
      
      close STDOUT or warn "$0: close: $!";
      
      __DATA__
      This = assignment is ok
      But := not this
      And == definitely not this
      

      输出:

      $ ./lasterr
      == 绝对不是这个

      对于正则表达式,当您希望模式的最后一次出现时,将^.* 放在模式的前面。例如,要将输入中的最后一个 X 替换为 Y,请使用

      $ echo XABCXXXQQQQXX | perl -pe 's/^(.*)X/$1Y/'
      XABCXXXQQQQXY

      注意^ 是多余的,因为regular-expression quantifiers 是贪婪的,但我喜欢用它来强调。

      将此技术应用于您的问题,您可以在配置文件中搜索包含错误的最后一行,如以下程序中所示:

      #! /usr/bin/perl
      
      use warnings;
      use strict;
      
      local $_ = do { local $/; scalar <DATA> };
      if (/\A.* ^(?! \w+ \s+ = \s+ [^\r\n]+ $) (.+?)$/smx) {
        print $1, "\n";
      }
      
      __DATA__
      This = assignment is ok
      But := not this
      And == definitely not this
      

      正则表达式的语法有点不同,因为$_包含多行,但原理是一样的。 \A^ 类似,但它只匹配要搜索的字符串开头的 。使用/m switch (“multi-line”)^ 匹配逻辑行边界。

      到目前为止,我们已经知道了模式

      /\A.* ^ .../
      

      匹配最后一行看起来像的东西。 negative look-ahead assertion (?!...) 查找不是合法配置行的行。通常. 匹配除换行符以外的任何字符,但/s switch (“single line”) 解除了此限制。指定[^\r\n]+,即一个或多个既不是回车也不是换行的字符,不允许匹配溢出到下一行。

      Look-around assertions 不捕获,所以我们用(.+?)$ 抓住违规行。在这种情况下使用. 是安全的原因是因为我们知道当前行是错误的并且non-greedy quantifier +? 会尽快停止匹配,在这种情况下是当前逻辑行的结尾。

      所有这些正则表达式都使用/x switch (“extended mode”) 来允许额外的空格:目的是提高可读性。

      【讨论】:

        猜你喜欢
        • 2016-01-08
        • 1970-01-01
        • 2018-07-19
        • 2014-02-15
        • 2012-03-17
        • 1970-01-01
        • 2015-05-11
        • 2012-06-05
        • 2011-04-19
        相关资源
        最近更新 更多