Grep word after last occurance of string and display next few lines

Hi,

I wanted to grep string "ERROR" and "WORNING" after last occurrence of String "Starting" only and wanted to display two lines after searched ERROR and WORNING string and one line before. I have following cronjob log file "errorlog" file and I have written the code for same in Unix as below and working fine but not able to implement it in SunSolari.

Please find errorlog file as below :

it is Starting 
line1
line2
ERROR
line3
line4

it is Starting
line5
ERROR
line6
line7

it is Starting
line8
WARNING
line8.8
line8.9
line9
ERROR
line10
line11

Expected output something like as follow :

line8
WARNING
line8.8

line9
ERROR
line10

Following code is working in UNIX/LINUX but not working in SunSolari

ERROR="ERROR:"
WARNING="WARNING" 
 ERR=$ERROR"\|"$WARNING

awk  '/Starting/{if(b) exit; else b=1}1' $filename | grep -A3 -in "$ERR" 

Please advise :slight_smile:

Try:

nawk '/Starting/ { N=0 } {L[++N]=$0 } END { for(X=1; (X<=N)&&(X <= 3); X++) print L[X] }' inputfile

It keeps a list of lines in the array L, and every time it encounters 'Started', resets the count to zero and starts over. Adjust the <= 3 to taste.

1 Like

Hi.

Using part of Corona688's solution:

#!/usr/bin/env bash

# @(#) s2       Demonstrate extraction of lines before and after match.

if uname -a | grep -i solaris 
then
  echo " ( Note -using ggrep )"
  G=/usr/sfw/bin/ggrep
else
  echo " ( Note -using grep )"
  G=grep
fi

# Utility functions: print-as-echo, print-line-with-visual-space, debug.
# export PATH="/usr/local/bin:/usr/bin:/bin"
pe() { for _i;do printf "%s" "$_i";done; printf "\n"; }
pl() { pe;pe "-----" ;pe "$*"; }
db() { ( printf " db, ";for _i;do printf "%s" "$_i";done;printf "\n" ) >&2 ; }
db() { : ; }
C=$HOME/bin/context && [ -f $C ] && $C nawk $G

FILE=${1-data1}

pl " Input data file $FILE:"
cat $FILE

pl " Expected output:"
cat expected-output.txt

pl " Results:"
nawk '/Starting/ { N=0 } {L[++N]=$0 } END { for(X=1; (X<=N); X++) print L[X] }' $FILE |
$G -E -A2 -B1 -i 'error|warning' 

exit 0

producing:

$ ./s2
SunOS vm-solaris 5.10 Generic_137138-09 i86pc i386 i86pc
 ( Note -using ggrep )

Environment: LC_ALL = POSIX, LANG = POSIX
(Versions displayed with local utility "version")
OS, ker|rel, machine: SunOS, 5.10, i86pc
Distribution        : Solaris 10 10/08 s10x_u6wos_07b X86
bash GNU bash 3.00.16
nawk - ( /usr/bin/nawk, Jan 8 2007 )
/usr/sfw/bin/ggrep grep (GNU grep) 2.5

-----
 Input data file data1:
it is Starting 
line1
line2
ERROR
line3
line4

it is Starting
line5
ERROR
line6
line7

it is Starting
line8
WARNING
line8.8
line8.9
line9
ERROR
line10
line11

-----
 Expected output:
line8
WARNING
line8.8

line9
ERROR
line10

-----
 Results:
line8
WARNING
line8.8
line8.9
line9
ERROR
line10
line11

See man pages for details.

Best wishes ... cheers, drl

1 Like

Try also:

tac file | awk '{T[NR%3]=$0} /ERROR|WARNING/ {L=NR+1; print T[(NR+1)%3];print T[(NR+2)%3]; print; next} NR<=L; /Starting/ {exit}'  |tac
line8
WARNING
line8.8
line8.9
line9
ERROR
line10
line11
1 Like

I have given example of file, but not sure how many time "Starting" string is present in file.
I want only from last occurrence of string("Starting")to end of file where file has "ERROR" or "EXCEPTION".

Thanks :slight_smile:

Could you please give me one example of a UNIX/LINUX system where the above sequence of commands produces the expected output you showed us above when given the sample errorlog file you provided above as input?

I would expect the above code to display a subset of the text starting with the 1st line of the file and ending on the line before the 2nd line in the file that contains the string "Starting"; not a subset of the text starting with the last occurrence of the string "Starting" and ending at the end of the file.

Thanks for correction "Don Cragun",

Following code displays ERROR and WARNING from first 'Starting' occurance to second.

But I wanted from last to end of file in UNIX/LINUX also to solve this problem

ERROR="ERROR:"
WARNING="WARNING" 
 ERR=$ERROR"\|"$WARNING

awk  '/Starting/{if(b) exit; else b=1}1' $filename | grep -A3 -in "$ERR"

Please guide me.

With the : after ERROR marked in red above, I don't see how you got ERROR lines output either. I'm short on time today, (and this hasn't been tested), but try something more like:

ERROR="ERROR"
WARNING="WARNING"
ERR="$ERROR|$WARNING"

ed -s "$filename" <<-"EOF" | grep -E -A3 -in "$ERR"
        ?Starting?,$p
        q
EOF

Thanks "Don Cragun",

This code is giving following error :

 syntax error at line : 5 `<<' unmatched

If you entered:

ed -s "$filename" <<-"EOF"

exactly as shown above and you got that diagnostic (and you're using a Solaris/SunOS system), try running the script with /usr/xpg4/bin/sh instead of /bin/sh .

nawk '
  /ERROR|WARNING/ {if (cnt==0) s=s (s?RS:s) b; cnt=3}
  cnt&&cnt-- {s=s RS $0}
  /Starting/ {s=""; cnt=0}
  {b=$0}
  END {print s}
' errorlog
1 Like

Hi MadeInGermoney,

nawk '  /ERROR|WARNING/ {if (cnt==0) s=s (s?RS:s) b; cnt=3}  cnt&&cnt-- {s=s RS $0}  /Starting/ {s=""; cnt=0}  {b=$0}  END {print s}' errorlog

is not working in Linux environment.

In Linux it's just awk
(In Solaris it's nawk or /usr/xpg4/bin/awk ).

Hi MadeInGermany,

Following script is displaying from Last occurance "Starting" to end of file, but not searching ERROR/WARNING within that block.

Please guide me how to get next two lines with ERROR/WARNING within that block.

awk '  /ERROR|WARNING/ {if (cnt==0) s=s (s?RS:s) b; cnt=3}  cnt&&cnt-- {s=s RS $0}  /Starting/ {s=""; cnt=0}  {b=$0}  END {print s}' errorlog

---------- Post updated at 03:26 PM ---------- Previous update was at 02:59 PM ----------

when I have given following code it is displaying properly from last occurance 'Starting' to end of file, searching ERROR/WARNING and redirecting it in "Extractfile" also, but line number is displaying wrong in grep. Please advise me.

 
ERROR="ERROR"
WARNING="WARNING"
ERR=$ERROR"\|"$WARNING
ERRFILE="Extractfile"
 
awk '{if (cnt==0) s=s (s?RS:s) b; cnt=3}cnt&&cnt-- {s=s RS $0}/Starting/ {s=""; cnt=0}{b=$0}END {print s}' $file | grep -A3 -in "$ERR" >> $ERRFILE
in solaris grep -A switch does not work try using this grep instead

/usr/sfw/bin/ggrep -A3

In your first post you wanted a "before" line (that my awk script stored in the b variable) and 2 "after" lines.
Without "before" line and 3 "after" lines:

awk 'cnt&&cnt-- {s=s RS $0} /ERROR|WARNING/ {if (cnt==0) s=s (s?RS:s) $0; cnt=3} /Starting/ {s=""; cnt=0} END {print s}' errorlog

Actually, after throwing away everything in the sample input before the last line containing "Starting", the command:

grep -E -A3 -in 'WARNING|ERROR'

(the original command line nes provided [except it was missing the -E]) on the remaining text would produce:

3:WARNING
4-line8.8
5-line8.9
6-line9
7:ERROR
8-line10
9-line11

and accept ERROR and WARNING in mixed case (not just in all caps). You and I could duplicate this in awk, but it is complex enough that I didn't want to take the time to reinvent what grep already does so well. I thought we just needed to extract the final lines from errlog and feed them into the grep command nes had already supplied.

When I tried the following code in SUNOS systeam for small file it is working fine, but if I am using same commnad for 1000 to 10000 lines of file. following code is not working in Sunos systeam.

ERRFILE="outputfile"
 
nl $file | tac | awk '{T[NR%3]=$0} /ERROR|WARNING/ {L=NR+1; print T[(NR+1)%3];print T[(NR+2)%3]; print; next} NR<=L; /Starting/ {exit}'  |tac >> $ERRFILE

---------- Post updated at 10:22 AM ---------- Previous update was at 10:15 AM ----------

Following small file :

it is Starting line1line2ERRORline3line4it is Startingline5ERRORline6line7it is Startingline8WARNINGline8.8line8.9line9ERRORline10line11

And getting with line number but not counting blank line for small file as below :

    13  line8
    14  WARNING
    15  line8.8
    16  line8.9
    17  line9
    18  ERROR
    19  line10
    20  line11