views:

36

answers:

3

What I'm trying to do: Make a bash script that performs some tests on my system, wich than reads some log files, and in the end points me some analyzes.

I have, for example, a log file (and although it's not so big sometimes, I want to save proccess when possible) that has in the end something like this:

Ran 6 tests with 1 failures and 0 errors in 1.042 seconds.
Tearing down left over layers:
Tear down Products.PloneTestCase.layer.PloneSite in 0.463 seconds.
Tear down Products.PloneTestCase.layer.ZCML in 0.008 seconds.

And I already have this bash line, that takes the line I want (the one with failures and errors):

error_line=$(tac $p.log | grep -m 1 '[1-9] .* \(failures\|errors\)')

Obs: Could anyone answer me if 'tac' passes the proccess to grep for each line of the file, or first it load the hole file on memory and than grep runs on the hole "memory variable"? Cause I was thinking in run the grep to each line, and when the line I want comes, I'd stop the "cating" proccess.
If it does work this way ("grepping" each line), when grep finds what it want (with the -m 1 option), it stops the tac proccess? How I'd do that?
Also, do you know a better way?

Continuing...

So, the result of the command is:

Ran 6 tests with 1 failures and 0 errors in 1.042 seconds.

Now, I want to check that both the '1' AND the '0' values on the $error_line variable are equal to 0 (like they're not on this case), so that if any of them is different I can perform some other proccess to sinalyze that some error or failure was found.

Answers?

A: 

awk:

/^Ran / {
  print "No failures: " ($5 == 0)
  print "No errors: " ($8 == 0)
}
Ignacio Vazquez-Abrams
@Ignacio How I use awk to assign the $5 variable to some bash variable, so that I can use this external-variable on other part of my bash script?
Gabriel L. Oliveira
I.e., on this line: tac nsi.metadataextractor.log | grep -m 1 '[1-9] .* \(failures\)' | awk '{.....your code to assigh variables here..... }'
Gabriel L. Oliveira
Your two options are to print out `$5` and `$8`, capture the output in a bash variable, and then use parameter expansion to separate them after, or to continue processing further in awk.
Ignacio Vazquez-Abrams
Ended with: failures=$(echo $error_message | awk '{print $5}') errors=$(echo $error_message | awk '{print $8}')
Gabriel L. Oliveira
A: 

for very big log files, its better to use grep first to find the patterns you need, then awk to do other processing.

   grep "^Ran" very_big_log_file | awk '{print $5$8=="00"?"no failure":"failure"}'

Otherwise, just awk will do.

awk '{print $5$8=="00"?"no failure":"failure"}'
ghostdog74
+1  A: 

When grep exits because the pattern is found, a SIGPIPE is sent to tac causing it to exit so it won't continue to run needlessly.

read failures errors <<< $(tac $p.log | grep -Pom 1 '(?<= )[0-9]*(?= *(failures|errors))')
if [[ $failures == 0 && $errors == 0 ]]
then
    echo "success"
else
    echo "failure"
fi

The grep command will output only the numbers found preceding the words "failures" and "errors" without outputting any of the other text on the line.

Edit:

If your grep doesn't have -P, change the first line above to:

read failures errors <<< $(tac $p.log | grep -om 1 ' [0-9]* *\(failures\|errors\)' | cut -d ' ' -f 2

or, to use a variation of Ignacio's answer, to:

read failures errors <<< $(tac $p.log | awk '/^Ran/ {printf "%s\n%s\n", $5, $8}'
Dennis Williamson
@Dennis This is not working on my system as -P option is only allowed when compiled grep with --enable-perl-regexp. Could you tell me a solution without the -P option? Because you're the closer one to my answer.
Gabriel L. Oliveira
@Gabriel: See my edit.
Dennis Williamson
@Dennis Thank you. Sorry, this is the last question. What if the row changes between 2 patters, i.e., sometimes it starts with "Ran ", sometimes it starts with "Total: ". How would be the regex? (If it's not too much to ask, on both solutions?)
Gabriel L. Oliveira
@Gabriel: For the AWK version: `/^Ran|^Total:/`
Dennis Williamson
@Dennis: Thank you. Solved using: tac $p.log | grep -om 1 ' \*\\(Ran\|Total:\\) .* *\\(failures\|errors\\)' | grep -om 1 ' [0-9]\* *\\(failures\|errors\\)' | cut -d ' ' -f 2
Gabriel L. Oliveira