You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Perl while循环仅输出最后一行问题及日志时间排序需求

日志读取与按时间合并的解决方案

咱们一步步来搞定你的问题:原代码只输出最后一行是因为每次循环都覆盖了数组,直接push拆分字段又会把所有内容揉成一维数组导致格式混乱。先解决完整输出日志的问题,再实现按时间合并的需求。

一、原代码问题分析

你写的while (my $line = <IN1>) { @fields1 = split " ", $line; }每次循环都会把@fields1重新赋值为当前行的拆分结果,循环结束后自然只保留最后一行内容。如果用push(@fields1 , split " ", $line),所有行的字段会被压进同一个一维数组,格式肯定混乱。

二、第一步:实现完整日志输出

要完整保存并输出日志,我们可以把每一行的字段存为二维数组(每行是一个独立的数组元素),这样就能保留所有行的结构。修改后的代码如下:

#!/usr/bin/perl
use warnings;
use strict;

my $log1_file = "log1.log";
my $log2_file = "log2.log";

# 读取Log1到二维数组
open(my $in1, "<", $log1_file) or die "Could not open file $log1_file: $!";
my @log1;
while (my $line = <$in1>) {
    chomp $line;
    next if $line =~ /^\s*$/; # 跳过空行
    my @fields = split /\s+/, $line;
    push @log1, \@fields;
}
close $in1;

# 读取Log2到二维数组
open(my $in2, "<", $log2_file) or die "Could not open file $log2_file: $!";
my @log2;
while (my $line = <$in2>) {
    chomp $line;
    next if $line =~ /^\s*$/;
    my @fields = split /\s+/, $line;
    push @log2, \@fields;
}
close $in2;

# 输出完整Log1
foreach my $row (@log1) {
    print join(" ", @$row) . "\n";
}
print "\n"; # 空行分隔两个日志

# 输出完整Log2
foreach my $row (@log2) {
    print join(" ", @$row) . "\n";
}

运行这段代码就能得到你期望的完整日志输出,每行内容都会被正确保留并打印。

三、第二步:按Time字段合并排序输出

因为两个日志本身都是按Time递增排列的,我们用双指针法就能高效合并,完全基于标准Perl实现,不需要额外模块:

  1. 用两个指针分别指向两个日志的数据行(跳过表头,因为表头只需要输出一次)
  2. 循环比较当前指针指向行的Time值,输出Time较小的那一行,然后移动对应指针
  3. 当其中一个日志遍历完后,输出另一个日志剩下的所有行

代码实现如下:

#!/usr/bin/perl
use warnings;
use strict;

my $log1_file = "log1.log";
my $log2_file = "log2.log";

# 读取Log1,保存表头和数据行
open(my $in1, "<", $log1_file) or die "Could not open file $log1_file: $!";
my @log1;
while (my $line = <$in1>) {
    chomp $line;
    next if $line =~ /^\s*$/;
    my @fields = split /\s+/, $line;
    push @log1, \@fields;
}
close $in1;

# 读取Log2,保存表头和数据行
open(my $in2, "<", $log2_file) or die "Could not open file $log2_file: $!";
my @log2;
while (my $line = <$in2>) {
    chomp $line;
    next if $line =~ /^\s*$/;
    my @fields = split /\s+/, $line;
    push @log2, \@fields;
}
close $in2;

# 先输出表头(两个日志表头一致,取Log1的即可)
print join(" ", @{$log1[0]}) . "\n";

# 双指针合并数据行
my $i = 1; # Log1的数据行从索引1开始(索引0是表头)
my $j = 1; # Log2的数据行从索引1开始

while ($i <= $#log1 && $j <= $#log2) {
    my $time1 = $log1[$i][0];
    my $time2 = $log2[$j][0];
    
    if ($time1 <= $time2) {
        print join(" ", @{$log1[$i]}) . "\n";
        $i++;
    } else {
        print join(" ", @{$log2[$j]}) . "\n";
        $j++;
    }
}

# 输出Log1剩余的行
while ($i <= $#log1) {
    print join(" ", @{$log1[$i]}) . "\n";
    $i++;
}

# 输出Log2剩余的行
while ($j <= $#log2) {
    print join(" ", @{$log2[$j]}) . "\n";
    $j++;
}

运行后会得到按Time从小到大排序的合并日志,输出效果如下:

Time Src_id Des_id Address
0 34 56 x9870
1 35 57 x9871
2 36 58 x9872
3 37 59 x9873
4 38 60 x9874
5 39 61 x9875
6 40 62 x9876
7 41 63 x9877
8 42 64 x9878
9 43 65 x9879

补充小细节

  • 用open(my $in1, "<", $file)这种三参数写法比旧式的open(IN1, "<$file")更安全,能避免文件名里的特殊字符引发问题
  • chomp $line用来去掉每行末尾的换行符,防止输出多余空行
  • 跳过空行的处理是为了兼容日志里可能存在的空白行,让代码更健壮

内容的提问来源于stack exchange,提问作者Alexx

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 09:07:45