Raj
Raj

Reputation: 767

using sed in perl

I have a file with the following entries

--INFO----- Command processing: Name='shayam' Age='19' Project='Alwa'    
--ERROR---- Failed to process  
--INFO----- Command processing: Name='ram' Age='23' Project='Alwa'  
--INFO----- Command processing: Name='raja' Age='24' Project='Alwa'  
--INFO----- Command processing: Name='shyla' Age='27' Project='Alwa'  
--ERROR---- Failed to process

I need to extract Name and Age from the corresponding line for which error occurred. In this case, I need to extract Name=shayam, Age=19 and Name=shyla Age=27.

Upvotes: 0

Views: 552

Answers (6)

Greg Bacon
Greg Bacon

Reputation: 139701

This turns out to be one of the rare cases where redo is useful.

$ cat file.log
--INFO----- Command processing: Name='shayam' Age='19' Project='Alwa'    
--ERROR---- Failed to process  
--INFO----- Command processing: Name='ram' Age='23' Project='Alwa'  
--INFO----- Command processing: Name='raja' Age='24' Project='Alwa'  
--INFO----- Command processing: Name='shyla' Age='27' Project='Alwa'  
--ERROR---- Failed to process

$ perl -lne \
  '/^--INFO.+\b(Name=.+? Age=.+?'\'')/&&index($_=<>,"--ERROR")?redo:print$1' \
  file.log
Name='shayam' Age='19'
Name='shyla' Age='27'

For INFO entries, grab the name and age. If the following line begins with --ERROR, print the recorded parameters, but if not, ratchet forward, checking whether the following line is an info entry.

Upvotes: 0

Mike
Mike

Reputation: 21659

This is similar to the other answers here, just simplified a little:

#!/bin/perl -w
use strict;
my ($name, $age);
while(<>) {
    ($name, $age) = ($1, $2) if /Name='?([\w]+)'?\s+Age='?([\d]+)'?/;
    print "$name, $age\n" if /^--ERROR--/;
}

Usage example:

perl extract.pl input.log

Upvotes: 2

ShinTakezou
ShinTakezou

Reputation: 9681

I would stick to the same approch of the other answer to the similar question, simply storing the last INFO found so far

$p = "";
while(<>) {
    if ( /^--INFO/ ) { $p = $_; next; }
    next if !/^--ERROR/;
    $p =~ /Name='([^']+)'\s+Age='([^']+)'/;
    print $1, "  ", $2, "\n";
}

Upvotes: 2

marco
marco

Reputation: 4675

Try with:

sed -n "\$!N;/--ERROR----/{s/.*Name='\([^']*\)' Age='\([^']*\)'.*/Name=\1 Age=\2/p}" file

If you are using bash, you may have to disable history substitution:

set +H

Upvotes: 0

paxdiablo
paxdiablo

Reputation: 882606

I would start with:

$ echo "--INFO----- Command processing: Name='shayam' Age='19' Project='Alwa'
--ERROR---- Failed to process
--INFO----- Command processing: Name='ram' Age='23' Project='Alwa'
--INFO----- Command processing: Name='raja' Age='24' Project='Alwa'
--INFO----- Command processing: Name='shyla' Age='27' Project='Alwa'
--ERROR---- Failed to process " | perl -ne '
    if (/^--INFO--/) {@line = split;}
    if (/^--ERROR--/) {print "$line[3] $line[4]\n";}'

which produces:

Name='shayam' Age='19'
Name='shyla' Age='27'

All it does is store the information from every INFO line and then print it out when you get an ERROR line.

You'll notice it still has the quotes around the values but, if you really want to get rid of those, use the (very simplistic) proc.pl script:

#!/bin/perl -w
while (<STDIN>) {
    if (/^--INFO--/) {
        @line = split;
    }
    if (/^--ERROR--/) {
        $l3 = $line[3];
        $l4 = $line[4];
        $l3 =~ s/'//g;
        $l4 =~ s/'//g;
        print "$l3 $l4\n";
    }
}

Running this with:

$ echo "--INFO----- Command processing: Name='shayam' Age='19' Project='Alwa'
--ERROR---- Failed to process
--INFO----- Command processing: Name='ram' Age='23' Project='Alwa'
--INFO----- Command processing: Name='raja' Age='24' Project='Alwa'
--INFO----- Command processing: Name='shyla' Age='27' Project='Alwa'
--ERROR---- Failed to process " | ./proc.pl

gives:

Name=shayam Age=19
Name=shyla Age=27

You can use any input file or stream with that (for example):

cat file.txt | ./proc.pl

or:

./proc.pl <file.txt

Upvotes: 1

Benjamin Oakes
Benjamin Oakes

Reputation: 12782

I'm not sure if I understand the title of this question. If you're programming using Perl, you could use a regex to capture the information like so:

/Name='(.*?)' Age='(.*?)'/

The name will be in $1 and the age will be in $2.

Upvotes: 1

Related Questions