stevo
stevo

Reputation: 181

Forward and reverse search in file after matching string with BASH

I have a large file that consists of tests run sequentially. Each test has a test name and test data. I want filter out all tests that failed into a separate file. - The test names are enclosed in square brackets. - The test data in the example below are the 4 lines in each test - If a test fails it will have the keyword FAILED in it. Here is a simple example:

[CPU]
aaaa
bbbb
cccc
[Drives]
dddd
FAILED eeee
ffff
[Memory]
gggg
hhhh
iiii
[Power]
FAILED jjjj
FAILED kkkk
llll
[Graphics]
mmmm
nnnn
oooo

In this example 2 of the 5 tests failed so the output file would be:

[Drives]
dddd
FAILED eeee
ffff
[Power]
FAILED jjjj
FAILED kkkk
llll

Using BASH I can use grep to find the failed lines but I don't know how I can extract the full tests including the test names. I was thinking that after finding a match with grep I would use a do while loop and output each line to the file until it finds the [] above and below it.

Upvotes: 1

Views: 1939

Answers (3)

Kalanidhi
Kalanidhi

Reputation: 5092

You can also use sed command

sed ':a;N;/\[.*\]$/{/.*FAILED.*\n/{P;D};D;t};s/\n/-/g;$d;t a;' file_name | sed 's/-/\n/g'

Explanation:

N   -- Get the two line and store in the pattern space . 
t a -- continue the loop and append the line to the pattern space 
P   -- Print the first line in the pattern space .
D   -- Delete the first line in the pattern space .

Execution way:

N get the two line and t loop append each line into the pattern space until the next block of header. After the header all the lines are considered as a single line by using substitution. Then some validation is performed like if FAILED pattern is found then print the until newline is found and delete it, else delete the line until newline, then continue the process. Finished all the process then substitute the every field with newline.

Upvotes: 2

user3620917
user3620917

Reputation:

The first thing that comes to my mind is very ugly solution with temporary files:

split -l 4 --additional-suffix=.txt yourfile.txt tmpfile; grep -C 4 FAILED tmpfile*.txt

It is definitely not most efficient but could be useful especially if (as you wrote) you want to store failed output in separate files anyway.

Upvotes: 1

konsolebox
konsolebox

Reputation: 75498

Using GNU awk:

gawk -v RS='\\[[^\\]]+\\]' /FAILED/ { printf "%s%s", p, $0 } { p = RT }' file

Output:

[Drives]
dddd
FAILED eeee
ffff
[Power]
FAILED jjjj
FAILED kkkk
llll

Upvotes: 0

Related Questions