2014-05-12 2 views
0

dmesg 출력처럼 보이는 여러 로그 파일을 구문 분석해야합니다.perl을 사용하여 텍스트 파일에서 정보를 추출하십시오.

예 로그 파일 :

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

나는 작업 ID, 클라이언트, 디스크 볼륨, 디스크 풀을, 파일 출력에 인쇄해야
.... 
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; 
.... 

등 때문에 출력 파일과 같이 표시됩니다

나는이 일을 시도하여 취업했다 :

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

fh는 어디입니까?

하지만 줄의 첫 번째 숫자, 즉 타임 스탬프 만 반환합니다.

어떻게 클라이언트 이름이나 서버 이름을 얻을 수 있습니까?

이 문제가 해결 되었습니까?

답변

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

이 서버 이름이에 하이픈이있는 경우를 제외하고 잘 작동합니다. 예 : Server = 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 정규 표현식을 쉽게 사용할 수 있기를 바랍니다. 아래의 스크립트가 도움이 될 수 있습니다. 내가 얻은

#!/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 
관련 문제