trying to isolate a block from my logs with awk, help please!
I am trying to write an awk script that can get a block that contains the word "error", out of a long log file.
Basically this log file contains actions performed, and when one of these fails, it will add under the action the error line, saying what is wrong.
I can isolate easily the error line just doing a grep for "error:", but i am missing the command given since it is printed before the error line, and i do not know how many lines before, so cannot just arbitrarily say "print the 10 lines that precede the word "error:"
I've figured out a sort of scheme thou; each of the block that could contain the error lines starts in the same way ("ProcessName"), followed by the command and other parameters, each one on a different line, and the last line will always be an empty line.
So my idea is to use this block with awk, so i can look for the "processName" string, start to print the lines one by one until i reach the empty line, and then pipe the printed result trough a grep to see if there is the word "error:" in there; if there is an error then i will redirect on a file and append the whole block, otherwise it will continue to the next block and do the same thing.
Now it would really help if i can get a hand with this task; since I do not really know how could I achieve this; I've just looked at awk and it seems to be the right tool for the job (i can write a shell script for the task), but if you think that there is a better way to do it in a shell script, I am all ears :)
Thanks in advance for your help!
Update: Thanks for your scripts; i've got the one from Dennis to work but it prints the same block more than once, if there is more than one error entry in each block; while the example from bellisarius does not return any line.
I've added an example of what my log looks like, when i introduce an error (there is an empty line at the end, but cannot add it if i put the text in the tag code):
ProcessName
ID=1231
Command:"ls -l a"
Hash "gkfsmgflsdmgklsdmfldsmfklmdsflkmsdflmsdflkmsdflkmsdfklsdmfklsdmfklmsdfklmsdklfmsdklmflksdmflkdsmfkldsmfkldmslfmdslkfmklsdmflksdmfklsdmfkldmslfkmslfkmsdlkfm"
/filename/compileme.c:20: error: the directory does not exist
/filename/compileme.c:20: error: incorrect parameter
A re开发者_开发技巧gular block looks exactly the same, but does not have the error: part obviously.
Hope that this makes it more clear, thanks again!
You may try:
BEGIN {flag="no";k=0}
/ProcessName/ {flag="no";k=0}
/ProcessName/,/^$/ {a[k++]=$0;
if(match($0,"error")!= 0) {flag="yes"};
}
/^$/ {if (flag=="yes") {flag="no";
for ( i=0; i<k; i++ ){print a[i]}
print "-------";
};
for ( r in a ){delete a[r]};k=0;
}
Test:
Input:
ProcessName
adasd
asdasd
ProcessName with err
error
salutti
ProcessName no err
aaa
no err
ProcessName
Output:
ProcessName with err
error
salutti
-------
Running at ideone here
Edit
On your comment about having sometimes an empty record before the error record, you can solve that by pre-processing your log files with the following awk script that deletes the empty lines before the error messages:
/^$/ {getline; if($0 !~ /error/) print ""}
{print}
and then running the main script on the output of this one.
Give this a try
awk '/ProcessName/{a = $0; next} {a = a RS $0} /error:/{print a}' inputfile
It accumulates lines and resets the accumulator each time it sees "ProcessName". When it sees "error:" it prints the contents of the accumulator.
Next time, show some sample input
awk 'BEGIN{RS=""}/ProcessName/ && /Error/' file
$ cat file
ProcessName
adasd
asdasd
ProcessName with err
error
salutti
ProcessName no err
aaa
no err
$ awk 'BEGIN{RS=""}/ProcessName/ && /err/' file
ProcessName with err
error
salutti
ProcessName no err
aaa
no err
for blank-line delimited files, I find Perl easiest:
perl -00 -ne 'print if /^ProcessName/ && /error/' afile
The -00
option is the magic incantation to pass the file a paragraph at a time.
精彩评论