我正在尝试读取日志文件并将所有错误日志写入新文件。我还必须跟踪有多少错误以及总体消息数量。我必须假设日志将分为多行,因此我一直在使用正则表达式并串联变量来搜索所有可能性并写入适当的文件。 我的文件句柄是:FILE、ERRORFILE 和 SUCCESSFILE。
use strict;
use warnings;
my $totalcount = 0;
my $errorcount = 0;
my $log = "s"; # $log controls what what should be written where,
# incase it doesn't start with code.
# "s" = SuccessFile, "e" = ErrorFile
my $logStart = "y"; # used with m/^I/ or m/^E/ instead of full code
# incase the code is broken into pieces.
my $dash = 0;
while (<FILE>) {
$dash += () = $_ =~ m/-/g; # can't use tr/// because it counts at compile
if ( $dash lt 25 ) { next; } # this line skips "---Begin <Repository>---"
elsif ( m/[a-zA-Z <>]/ && $dash lt 25 ) { next; }
elsif ( $dash >= 26 ) { last; } #Ends loop at "---End <Repository>---"
if ( m/^I/ && $logStart eq "y" ) {
$log = "s";
$logStart = "n";
$totalcount++;
next;
} #Ignores nonerror logs
elsif ( m/^E/ && $logStart eq "y" ) {
chomp $_;
print ERRORFILE "$_";
$errorcount++;
$totalcount++;
$log = "e";
$logStart = "n";
}
elsif (m/ \.\n$/) { #End of log
if ( $log eq "s" ) { $logStart = "y"; next; }
print ERRORFILE "$_\n" if $log eq "e";
$logStart = "y";
}
else { #line doesn't start with code or end in " .\n"
chomp $_;
print ERRORFILE "$_" if $log eq "e";
next if $log eq "s";
}
}
print "\nThere are $errorcount error logs.\n";
print "There are $totalcount logs in the full log file.\n";
我知道非错误日志以 I00020036 开头,错误日志以 E03020039 开头。两者都以“.\n”结尾
---------- Begin <Load Repository> ---------------
I00020036: Loaded C:\Documents and Settings\dorja03\Desktop\DSMProduct\external\etpki\Linux_2.4_x86\redistrib\readme.txt into \DSM R11\external\etpki\Linux_2.4_x86\redistrib\readme.txt .
E03020039: Unable to load C:\Documents and Settings\dorja03\Desktop\DSMProduct\external\etpki\Linux_2.4_x86\redistrib\etpki_install_lib.sh into \DSM R11\external\etpki\Linux_2.4_x86\redistrib\etpki_install_lib.sh . Text file contains invalid characters .
---------- End <Load Repository> ---------------
我一直在运行一个包含两行的测试样本。如果错误首先出现,它将与非错误日志一起打印到错误文件中,并在同一行上。如果非错误在先,则它不会识别错误。
这是因为我使用了 m//错误还是完全是其他原因?
编辑:已添加测试输入。我还添加了跳过页眉和页脚的代码。
测试输出:如果首先出现非错误,则错误数为 0,日志总数为 1。 如果先出现非错误,则总共有 1 个错误和 1 个日志。
如果这有效,它应该显示有 1 个错误和 2 个日志。它还只会将错误打印到 ERRORFILE。
最佳答案
这不会回答您的代码无法工作的原因,但我将如何解决该问题:
由于日志可以跨越多行,因此可以通过调整
$/
来修改默认的逐行行为。 .使用适当的数据结构从非错误中过滤错误。这还允许您将打印推迟到以后。
代码将如下所示:
use strict;
use warnings;
my %logs;
local $/ = " .\n";
while ( <> ) { # Now $_ is the full (multi-line) log
next if /--- Begin/; # Skip if /Begin/
last if /--- End/; # Stop processing if /End/
if ( m/^I/ ) {
push @{ $logs{nonerror} }, $_;
}
if ( m/^E/ ) {
push @{ $logs{error} }, $_;
}
}
printf "There are %d error logs\n.", scalar @{ $logs{error} // [] } ;
printf "There are %d logs in the full logfile.\n",
@{$logs{error} // []} + @{$logs{nonerror} // []};
我喜欢这种方法的地方:
- Perl 负责决定每条日志消息何时结束(完全消除
$logStart
变量)。 - 逻辑更容易扩展。
while
循环专用于处理日志文件(无需++
任何内容)。- 使用合理标记的数据结构而不是临时变量可以简化代码维护。
关于regex - 在 Perl 中使用正则表达式对行进行排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23199259/