Perl - 逐行读取命令输出文件

时间:2013-12-09 03:22:52

标签: perl file

我有一个日志文件,其中包含在每台服务器上运行的几个命令的输出。格式类似于

APRHY01> lt all
131119-15:41:39 10.105.219.68 10.0b  stopfile=/tmp/27599
Checking MOM version...RNC_NODE_MODEL_M_1_200
Parsing MOM (cached): /home/ekisjay/moshell//jarxml/RNC_NODE_MODEL_M_1_200.xml.cache.gz Done.
.............
.
.
.
APRHY01> alt
131119-15:41:55 10.105.219.68 10.0b RNC_NODE_MODEL_M_1_200 stopfile=/tmp/27599
Connecting to 10.105.219.68:56834 (CorbaSecurity=OFF, corba_class=2, java=1.6.0_26, jacoms=R73D19, jacorb=R73D01)
Starting to retrieve active alarms
Nr of active alarms are: 3

APRHY01> strt
131119-15:41:58 10.105.219.68 10.0b RNC_NODE_MODEL_M_1_200 stopfile=/tmp/27599

Following 326 sites are up:
---------------------------------------------------------------------------------------------------------------------
 MOD  IUBLINK    CELLNAMES        CFRPHEM1 CFRPHEM2 CFRPHEM3 CFRPHEM4 CFRPHEM5 CFRPHEM6 ICDS   TN ATMPORTS
---------------------------------------------------------------------------------------------------------------------
  21  Iub_00023  UHYD494-X        111111                                                1  1    I
  21  Iub_00032  UHY4100-X        111111                                                1  1    I

然后对于下一个服务器或节点重复...

APRHY02> lt all

131119-15:44:51 10.105.219.4 10.0b  stopfile=/tmp/2874
Checking MOM version...RNC_NODE_MODEL_M_1_200
Parsing MOM (cached): /home/ekisjay/moshell//jarxml/RNC_NODE_MODEL_M_1_200.xml.cache.gz Done.
Using paramfile /home/ekisjay/moshell//commonjars/pm/PARAM_RNC_M_1_50.txt
Parsing
 file /home/ekisjay/moshell//commonjars/pm/PARAM_RNC_M_1_50.txt ...

我必须在每个节点的每个命令之间占用几行(根据要求中所述的条件)。我在逐行读取时编写了一个perl程序,并在与/[A-Z][A-Z][A-Z][A-Z][A-Z][0-9][0-9]\>之类的命令匹配的每一行停止,然后在下一个命令行之间和之前检索所需的行并将其写入另一个文件。在循环中,我的程序实际上跳过了一个命令,然后转到下一个命令(第1,第3,第5种......)。任何人都可以帮助我吗?

3 个答案:

答案 0 :(得分:0)

您尚未向我们展示您用于解析文件的代码,因此很难说它可能出现的问题: - )

为了打破这样的多行日志输出,一个好方法是遍历文件,将行附加到文本块,直到找到下一个块的第一行 - 然后刷新块''从当前行开始,一直在追加并创建一个新的。

my $block = "";
while (<>) {
    if (/[A-Z][A-Z][A-Z][A-Z][A-Z][0-9][0-9]\>/) {
        write_block($block) if $block;
        $block = "";
    }
    $block .= $_;
}
write_block($block);

答案 1 :(得分:0)

也许以下内容会有所帮助:

use strict;
use warnings;

my ( $fileName, $fh, $i );

while (<>) {
    if ( !$fileName or $fileName ne $ARGV ) {
        $fileName = $ARGV;
        $i        = 0;
    }

    if ( my ($cmd) = /^([A-Z]{5}\d{2}>.+)/ ) {
        $cmd =~ s/\W+/_/g;
        open $fh, '>', $cmd . '_' . ( sprintf '%05d', ++$i ) . '.txt' or die $!;
    }

    print $fh $_;
}

命令行用法:>perl script.pl logFile1 [logFile2 .. logFileN]

[ ]表示法表示可选的多个文件。

该脚本使用正则表达式捕获命令/服务器行,然后使用下划线替换“非单词”字符,此加上计数加.txt将成为写入该命令文本块的文件名。因此,使用您的数据集,创建了包含命令内容的以下文本文件:

APRHY01_lt_all_00001.txt
APRHY01_alt_00002.txt
APRHY01_strt_00003.txt
APRHY02_lt_all_00001.txt
APRHY02_alt_00002.txt
APRHY02_strt_00003.txt

如果同一个命令多次发送到同一个服务器,则插入计数,因为这个数字可以为每个服务器保存单独的文件。

答案 2 :(得分:0)

  

代码:

my $srcFile = "new.log";
my $destFile = "deviations.log";
my @grabbed = {};
my $line = "";
open (my $src, "$srcFile") or die "Could not open the log file $srcFile: $!";
open (my $dest, ">>$destFile") or die "Could not open the destination file $destFile: $!";
while ($line = <$src>)
{ if ($line =~ /[A-Z][A-Z][A-Z][A-Z][A-Z][0-9][0-9]\>/)
  { push @grabbed, "Deviations of the output of command: $line\n";
    while ($line = <$src>)
    {if ($line !~ /[A-Z][A-Z][A-Z][A-Z][A-Z][0-9][0-9]\>/)
     {push @grabbed, $line;
     }
     else
     {last;
} } }}
print $dest "\n@grabbed";
close $dest;
close $src;

在查找新命令行时执行last,转到外部while ($line = <$src>),从而已经读取下一行(命令的第一个输出行)并且无法识别该命令的开头命令。一个简单的解决方法是通过标记外部循环并使用redo而不是last来省略新行的读取:

LINE:
while ($line = <$src>)
{ if ($line =~ /[A-Z][A-Z][A-Z][A-Z][A-Z][0-9][0-9]\>/)
  { push @grabbed, "Deviations of the output of command: $line\n";
    while ($line = <$src>)
    { if ($line !~ /[A-Z][A-Z][A-Z][A-Z][A-Z][0-9][0-9]\>/)
      { push @grabbed, $line }
      else
      { redo LINE }
} } }