2014-05-12 122 views
0

我必須解析看起來像dmesg輸出的多個日誌文件。使用Perl從文本文件中提取信息

示例日誌文件:

.... 
1399424400 4 abcd 2604 starting job (jobid=1325) for client abc.xyz.com, requesting resources now 
RESOURCE_GRANTED 1399424400 DiskVolume=/vol;DiskPool=pool1;Path=/mypath;Server=qwer.poil.com; 
.... 

我需要打印輸出文件的作業ID,客戶端,磁盤卷,盤池等,使輸出文件將是這樣的:

1325 abc.xyz.com /vol pool1 /mypath qwer.poil.com 
<file2 info> 
<file3 info> 
..... 

我試過這樣做以獲得jobid:

if(@grepres=grep{/jobid/} <TRY>){ 
@splitres=split(' ',$grepres[0]); 
$jobid=$splitres[1]; 
$jobid =~ s/\D//g; 

fh在哪裏?

但它只返回行中的第一個數字,即時間戳。

如何獲取客戶端名稱或服務器名稱?

這是perl approrpiate嗎?

回答

1

在重新格式化之前,您應該將每個文件所需的所有數據都放入哈希中。

該程序以您希望顯示在輸出中的字段名稱列表開始,並構建一個正則表達式,該正則表達式匹配那些後面跟着值的字段。

然後,只需要在文件的所有行中找到該模式的所有匹配項並將它們添加到散列中即可。

有一個最終檢查以確保所有必填字段都在散列中,然後將內容打印爲簡單散列片。

請問這是否有任何不清楚的地方。

use strict; 
use warnings; 

my @names = qw/ jobid client DiskVolume DiskPool Path Server /; 
my @files = qw/ dmesg1.txt dmesg2.txt dmesg3.txt /; 

my $re = join '|', @names; 
$re = qr{ \b($re)\b [\s=]+ ([\w./]+) }x; 

for my $filename (@files) { 

    open my $fh, '<', $filename or do { 
    warn "Can't open '$filename' for reading: $!"; 
    next; 
    }; 

    my %data; 
    while (my $line = <$fh>) { 
    $data{$1} = $2 while $line =~ /$re/g; 
    } 

    if (my @missing = grep { not exists $data{$_} } @names) { 
    warn sprintf 'Missing %s "%s" from file "%s"', 
     @missing == 1 ? 'field' : 'fields', 
     join(', ', @missing), 
     $filename; 
    next; 
    } 

    print "@data{@names}\n"; 
} 

輸出

1325 abc.xyz.com /vol pool1 /mypath qwer.poil.com 
+0

除了當服務器名稱中有一個連字符這個偉大的工程。示例如果它的服務器= qw-er.poil.com,它將只打印qw並忽略其餘部分。我將$ re改爲 $ re = qr {\ b($ re)\ b [\ s =] +([\ w - /] +)} x;現在它可以工作。謝謝! – user983043

+0

@ user983043:是的,我是這樣寫的,因爲在你的例子中沒有連字符。該字符類應該是'[\ w - 。/]',否則'qwer.poil.com'將不能正確匹配 – Borodin

1

如果所有行的格式都是相同的格式,則可以使用foreach循環並按照您的方式拆分每一行,同時使用該數組訪問每個所需的字段。嘗試這個。

my @logfile = <TRY>; 
close TRY; 

my $jobid; 

foreach my $line (@logfile) { 
    chomp $line; # remove trailing newline 

    # might be good to check for blank lines or anything invalid 
    if ($line !~ /^$/) { 
     my @splitres=split(' ',$line); 
     $jobid=$splitres[1]; 
     $jobid =~ s/\D//g; 

     # and so on with the remaining fields... 
    } 
} 
0

Perl的正則表達式將是您一個完美的解決方案。由於它是一個日誌文件,我希望這個格式不會改變,因此你可以很容易地使用Perl的正則表達式。下面的腳本可以幫助你。

#!/usr/bin/perl 
open (DATA,"<test") or print "cannot open test file"; 
open (DATA1,">test1") or print "cannot open test1 file"; 
while (<DATA>) 
{ 
if ($_=~/.*jobid=(\d+).*client\s*(\w+\.\w+\.\w+).*DiskVolume=(\/\w+).*DiskPool=(\w+).*Path=(\/\w+).*Server=(\w+\.\w+\.\w+).*/) 
{ 
print DATA1 "$1 $2 $3 $4 $5 $6\n"; 
} 
} 
close (DATA); 
close(DATA1); 

我所獲得的輸出是

[[email protected] perl]# cat test1 
1325 abc.xyz.com /vol pool1 /mypath qwer.poil.com