Reputation: 767
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
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
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
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
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
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
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