File Reading for a certain string and echo the line before

Hi Guys,

I have a big file like this. It has cache group line ( the bold lines ) and then followed by 10 status lines showing either Compelte or Failed. This pattern repeats several time. We can assume all the status lines have either Complete or Failed status for that Cache Group line.

I need to find a way to display just the failed cache group lines ( echo of that line ). Here I just want to see one line "call ttcacheautorefreshstatsget('CGOWNER','CG_CLIENT_PLAN');"

Have been struggling for a day but not finding a good solution. Can something like this be achieved using shell scripting or do I have to use perl ?

Hope I didn't confuse in explaining what I want.

call ttcacheautorefreshstatsget('CGOWNER','CG_CLIENT_NOTE');
< 2284744, 2012-03-08 22:57:11.000000, 24829530, 11422, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Complete >
< 2284744, 2012-03-08 22:57:09.000000, 24827530, 11421, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Complete >
< 2284744, 2012-03-08 22:57:07.000000, 24825530, 11420, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Complete >
< 2284744, 2012-03-08 22:57:05.000000, 24823530, 11419, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Complete >
< 2284744, 2012-03-08 22:57:03.000000, 24821520, 11418, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Complete >
< 2284744, 2012-03-08 22:57:01.000000, 24819520, 11417, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Complete >
< 2284744, 2012-03-08 22:56:59.000000, 24817520, 11416, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Complete >
< 2284744, 2012-03-08 22:56:57.000000, 24815520, 11415, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Complete >
< 2284744, 2012-03-08 22:56:55.000000, 24813520, 11414, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Complete >
< 2284744, 2012-03-08 22:56:53.000000, 24811520, 11413, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Complete >
10 rows found.

call ttcacheautorefreshstatsget('CGOWNER','CG_CLIENT_PLAN');
< 2285336, 2012-03-08 22:57:13.000000, 24830610, 2483, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Failed >
< 2285336, 2012-03-08 22:57:03.000000, 24820610, 2482, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Failed >
< 2285336, 2012-03-08 22:56:53.000000, 24810610, 2481, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Failed >
< 2285336, 2012-03-08 22:56:43.000000, 24800590, 2480, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Failed >
< 2285336, 2012-03-08 22:56:33.000000, 24790580, 2479, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Failed >
< 2285336, 2012-03-08 22:56:23.000000, 24780580, 2478, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Failed >
< 2285336, 2012-03-08 22:56:13.000000, 24770580, 2477, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Failed >
< 2285336, 2012-03-08 22:56:03.000000, 24760580, 2476, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Failed >
< 2285336, 2012-03-08 22:55:53.000000, 24750580, 2475, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Failed >
< 2285336, 2012-03-08 22:55:43.000000, 24740580, 2474, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Failed >
10 rows found.

Thanks in Advance
mkneni

I'd write a small awk to read the file and generate the desired output:

awk '
    $1 == "call" {
        buffer = $0;
        next;
    }

    /Failed/ {
        if( buffer  )
        {
            print buffer;
            buffer = "";
        }
    }
' input-log-file

Prints the 'call' line if any of the lines below it, before the next, are marked failed.

Alternatively try:

awk '/^call.*Failed/{print $1}' RS= FS='\n' infile

wow. Thank you both so much.

awk '/^call.*Failed/{print $1}' RS= FS='\n' infile worked good.

:slight_smile:

Just because the problem has been solved does not mean that the fun must come to an end. :wink:

sed -n '/Failed/{x;//!p;x;}; h' infile

Regards,
Alister

1 Like

@alister

I tried your code (on a SunOS 5.10 machine), it didn't work ( i have an output as below)

# awk '/^call.*Failed/{print $1}' RS= FS='\n' my
call ttcacheautorefreshstatsget('CGOWNER','CG_CLIENT_PLAN');
# sed -n '/Failed/{x;//!p;x;}; h' my










#

Scruti's code works fine by the way

Hi, ctsgnb:

Works fine for me with a BSD sed. Also, the script should be POSIX-compliant.

If you figure out why it fails on your implementation, I'd be interested to know; I'm not familiar with your system's userland.

Regards,
Alister

Some older seds don't play well without newlines. I was able to get it to work by inserting newlines.

sed -n '/Failed/{
x;
//!p;
x;
}; 
h' file
 

I was surprised that the 'one liner' didn't work with the version in xpg4 either.

1 Like

Ingenious and fun indeed!

Were you using /usr/xpg4/bin/sed ?

@alister :

Hi

Just to give a feedback : i gave a try inserting new line (as suggested by agama) , i confirm your code works fine that way

# sed -n '/Failed/{x
> //!p
> x
> }
> h' my
call ttcacheautorefreshstatsget('CGOWNER','CG_CLIENT_PLAN');
#

@Scruti

I also gave a try with /usr/xpg4/bin/sed : it doesn't work one line ... it looks it still need to be run in several lines :

# /usr/xpg4/bin/sed -n '/Failed/{x;//!p;x;}; h' my










#
# # /usr/xpg4/bin/sed -n '/Failed/{x
> //# !p
> x
> }
> h' my
call ttcacheautorefreshstatsget('CGOWNER','CG_CLIENT_PLAN');
#
2 Likes

Thanks for the feedback. I looked up the latest POSIX specification and I think indeed newlines should be used instead of semicolons...

sed: rationale

There is also this passage:

Editing Commands in sed

2 Likes

Although I already knew that those commands listed in your second quote should not be delimited by a semicolon, it's news to me that POSIX does not require it for the others.

Thank you very much for the POSIX enlightenment, Scrutinizer.

And thanks for reporting back, ctsgnb.

Regards,
Alister

@Scruti & Alister :

Just to validate that this is the handling of the semicolon after the {} clause that caused the error, i gave a last shot :

see :

# /usr/xpg4/bin/sed -n '/Failed/{x;//!p;x;};h' my










#
# /usr/xpg4/bin/sed -n '/Failed/{x;//!p;x;}
> h' my
call ttcacheautorefreshstatsget('CGOWNER','CG_CLIENT_PLAN');
#

... worked !

3 Likes

Nice job narrowing it down, ctsgnb.

Regards,
Alister