Perl - 在日志文件中搜索值并将其作为字符串存储/打印。

时间:2017-02-17 19:08:54

标签: string perl search

我想在日志文件中的特定单词(当前值=)之后搜索值,并创建一个包含值的字符串。

vcs_output.log:日志文件

** Fault injection **
  Count = 1533
  0: Path = cmp_top.iop.sparc0.exu.alu.byp_alu_rcc_data_e[6]
  0: Current value = x
  1: Path = cmp_top.iop.sparc0.exu.alu.byp_alu_rs3_data_e[51]
  1: Current value = x
  2: Path = cmp_top.iop.sparc0.exu.alu.byp_alu_rs1_data_e[3]
  2: Current value = 1
  3: Path = cmp_top.iop.sparc0.exu.alu.shft_alu_shift_out_e[18]
  3: Current value = 0
  4: Path = cmp_top.iop.sparc0.exu.alu.byp_alu_rs3_data_e[17]
  4: Current value = x
  5: Path = cmp_top.iop.sparc0.exu.alu.byp_alu_rs1_data_e[43]
  5: Current value = 0
  6: Path = cmp_top.iop.sparc0.exu.alu.byp_alu_rcc_data_e[38]
  6: Current value = x
  7: Path = cmp_top.iop.sparc0.exu.alu.byp_alu_rs2_data_e_l[30]
  7: Current value = 1
   .
   .
   .

如果我在“当前值=”之后存储值,则x,x,1,0,x,0,x,1。我最终将它们保存/打印为字符串,如xx10x0x1。

这是我的代码 code.pl:

#!/usr/bin/perl 

use strict;
use warnings;
##### Read input
open ( my $input_fh, '<', 'vcs_output.log' ) or die $!; 
chomp ( my @input = <$input_fh> );

my $i=0;
my @arr;
while (@input) {
    if (/Current value = /)
    $arr[i]= $input;  # put the matched value to array 
   }

}

## make a string from the array using an additional loop 

close ( $input_fh );

我认为有一种方法可以在一个循环中创建一个字符串(甚至不使用循环)。请指教我做。任何建议表示赞赏。

3 个答案:

答案 0 :(得分:1)

您可以使用捕获括号来获取所需的字符串:

use strict;
use warnings;

my @arr;
open ( my $input_fh, '<', 'vcs_output.log' ) or die $!; 
while (<$input_fh>) {
    if (/Current value = (.)/) {
        push @arr, $1;
    }
}
close ( $input_fh );
print "@arr\n";

__END__

x x 1 0 x 0 x 1

答案 1 :(得分:1)

你可以同时做两件事。

要直接构建字符串,只需将其在正则表达式中捕获的内容附加到

my $string;
while (<$input_fh>) 
{
    my ($val) = /Current\s*value\s*=\s*(.*)/;
    $string .= $val;
}

如果匹配失败,那么$val是一个空字符串,因此我们不必测试。您也可以在一行中编写整个while循环

$string .= (/Current\s*value\s*=\s*(.*)/)[0] while <$input_fh>;

但我不明白为什么那是必要的。请注意,这将从文件句柄中逐行读取。没有理由先将所有行读入数组。

为避免(显式)循环,您可以读取所有行并通过map传递它们,天真地将其作为

my $string = join '', 
    map { (/Current\s*value\s*=\s*(.*)/) ? $1 : () } <$input_fh>;

由于map需要列表,因此文件句柄位于列表上下文中,返回文件中所有行的列表。然后每个都由map块中的代码处理,然后连接其输出列表。

技巧map { ($test) ? $val : () }使用map同时执行grep的工作,过滤 - 如果$test失败则返回的空列表会变为输出列表,因此消失。这里的“测试”是正则表达式匹配,在标量上下文中返回true / false,而捕获集$1

但是,如上所述,我们可以返回匹配返回的列表的第一个元素,而不是测试匹配是否成功。由于我们在map,我们实际上可以返回“整个”列表

my $string = join '', 
    map { /Current\s*value\s*=\s*(.*)/ } <$input_fh>;

这里可能更清楚。

对问题中代码的评论

  • while (@input)是一个无限循环,因为@input永远不会耗尽。您需要foreach (@input) - 但最好只阅读文件句柄,while (<$input_fh>)

  • 你的正则表达式在与该字符串的行上匹配,但它不会尝试匹配您需要的模式(=后面的内容)。添加后,还需要通过()

  • 捕获
  • 你可以分配给第i个元素(应该是$i),但是你必须随时增加$i。大多数情况下,只有push @array, $value

  • 才会更好

答案 2 :(得分:0)

使用grepperlre
http://perldoc.perl.org/functions/grep.html
http://perldoc.perl.org/perlre.html

如果在非Unix环境中,那么......

#!/usr/bin/perl -w
use strict;

open (my $fh, '<', "vcs_output.log");

chomp (my @lines = <$fh>);

# Filter for lines which contain string 'Current value'
@lines = grep{/Current value/} @lines;

# Substitute out what we don't want... leaving us with the 'xx10x0x1'
@lines = map { $_ =~ s/.*Current value = //;$_} @lines;
my $str = join('', @lines);

print $str;

...否则

#!/usr/bin/perl -w
use strict;

my $output = `grep "Current value" vcs_output.log | sed 's/.*Current value = //'`;

$output =~ s/\n//g;
print $output;