3

For example, from this file:

CREATE SYNONYM I801XS07 FOR I8010.I801XT07
               *
ERROR at line 1:
ORA-00955: name is already used by an existing object


CREATE SYNONYM I801XS07 FOR I8010.I801XT07
               *
ERROR at line 1:
ORA-00955: name is already used by an existing object



Table altered.


Table altered.


Table altered.


Table altered.


Table altered.


Table altered.


Table altered.


Table altered.

DROP INDEX I8011I01
           *
ERROR at line 1:
ORA-01418: specified index does not exist



Index created.

I want a way to find ORA- and show the ORA- line and the previous 4 lines:

CREATE SYNONYM I801XS07 FOR I8010.I801XT07
               *
ERROR at line 1:
ORA-00955: name is already used by an existing object

CREATE SYNONYM I801XS07 FOR I8010.I801XT07
               *
ERROR at line 1:
ORA-00955: name is already used by an existing object

DROP INDEX I8011I01
           *
ERROR at line 1:
ORA-01418: specified index does not exist
Michael Mrozek
  • 93,103
  • 40
  • 240
  • 233

3 Answers3

9

The -B option to grep does exactly that: grep -B 4 ORA- your_file.

In the absence of GNU grep, I've adapted the grep4 example from the grymoire sed tutorial:

#!/bin/sh

# grepB4: prints out 4 lines before and the line including pattern
# if there is only one argument, exit

case $# in 
    1);;
    *) echo "Usage: $0 pattern";exit;;
esac;

sed -n '
'/"$1"/' !{
    # does not match - add this line to the hold space
    H
    # bring it back into the pattern space
    x
    # Two lines would look like .*\n.*
    # Three lines look like .*\n.*\n.*
    # Delete extra lines - keep four
    s/^.*\n\(.*\n.*\n.*\n.*\)$/\1/
    # put it back in hold space
    x
}
'/"$1"/' {
    # matches - append the current line
    H
    # bring hold space contents into pattern space
    g
    # print the 4 lines
    p
    # add the mark
    a\
---
}'

Usage: grepB4 pattern < file.

Bruce Ediger's answer does essentially the same thing with awk, which often has less cryptic syntax than sed.

jw013
  • 51,212
4

Supposing you're on an elderly system, like HP-UX, that doesn't have GNU utilities, just the old, original BSD or AT&T "grep". You could do something like this:

#!/bin/sh

awk '/ORA-/ { print line1; print line2; print line3; print line4; print $0 }\
// {line1 = line2; line2 = line3; line3 = line4; line4 = $0}' $1

Yes, there's tons of edge conditions this doesn't get right, but whatta ya want for nothing? Also, given that you're working on some decroded, antiquated OS and hardware, you probably don't have the CPU horsepower for fancy error handling.

1
awk 'NR == FNR && $0 ~ p {
  for (i = FNR; i >= FNR - l; i--)
    nr[i]; next
  }
FNR in nr  
BEGIN {
  ARGV[ARGC++] = ARGV[ARGC - 1]
  }' l=4 p=ORA- infile   

On Solaris use nawk or /usr/xpg4/bin/awk.