Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Pulling text out of a file 2

Status
Not open for further replies.

mcoop777

Technical User
Apr 9, 2002
1
US
I have to write a script that will grep for a string and then return the string plus 5 lines prior and 5 lines after.. Any Ideas
 
Try this awk script (with your pattern)

/pattern/{
for( i = 1; i <= 5; i++ )
if( length(A) > 0 )
print A
print
}
{
for( i=1; i < 5; i++ ) A = A[i + 1]
A[5]=$0
}


Cheers,
ND [smile]
 
Here's my answer in sed. If anyone else has an answer in sed, please let me know.

sed -nf '
/.*patten.*/p
N
/[^\n]*\n.*pattern.*/p
N
/[^\n]*\n[^\n]*\n.*pattern.*/p
N
/[^\n]*\n[^\n]*\n[^\n]*\n.*pattern.*/p
N
/[^\n]*\n[^\n]*\n[^\n]*\n[^\n]*\n.*pattern.*/p
:pos1
N
/[^\n]*\n[^\n]*\n[^\n]*\n[^\n]*\n[^\n]*\n.*pattern.*/p
/[^\n]*\n\([^\n]*\n[^\n]*\n[^\n]*\n[^\n]*\n.*\)/ s//\1/
b pos1
' file

Cheers,
ND [smile]
 
I was messing around with this and came up with this script. Give and shot and let me know what you think.

#!/bin/ksh
# grep_context.sh
# given a pattern and filename, for each occurrence of <pattern> found,
# print the preceding & following 5 lines

[ $# != 2 ] && {
echo &quot;Usage: $0 <pattern> <file>&quot;
exit 1
}

PATTERN=$1
FNAME=$2

# count lines in file
NUMLINES=$(cat $FNAME|wc -l|awk '{print $1}')

# for each occurrence of <pattern> found
for line in $(grep -n $PATTERN $FNAME|cut -d: -f1)
do
START=$((line -5))
[ $line -lt 5 ] && START=1
END=$((line + 5))
[ $END -gt $NUMLINES ] && END=$NUMLINES

sed -n ${START},${END}p $FNAME
done

Greg.
 
Whops! After reading grega's example I realized that I was doing just 5 lines prior, ahhhh! Here's one in awk that seems clunky and posibly unstable (all input goes to buffer), but it works. Maybe later I'll, or someone else, will get it better with awk or sed.

{
A[i++]=$0
}
END{
for( j = 0; j < i; j++ ){
if( A[j] ~ /pattern/ ){
for( k = (j<5 ? 0 : j-5); k < (j>i-6 ? i : j+6); k++ ) print A[k]
}
}
}

Cheers,
ND [smile]
 
grega -

I found that
grep_context.sh text foo
where foo contains the 6 lines:

a
b
c
d
text
e

produces no result. I believe the fix is to change line 17 from
[ $line -lt 5 ] && START=1
to
[ $line -le 5 ] && START=1

p.s. still no idea how to do in pure sed but a decent way in awk is:

Code:
BEGIN {
  LN=5
  SY=2*N
  SZ=SY + 1
}
{
  for( i=0; i < SZ; i++ ) A[i] = A[i + 1]
  A[SY]=$0
  if( A[LN] ~ /text/ ){
    for( j = (NR<SZ ? SZ-NR : 0); j < SZ; j++ ) print A[j]
  }
}
END {
  k = SZ
  while( k > LN ){
    for( i=0; i < SZ; i++ ) A[i] = A[i + 1]
    k--
    if( A[LN] ~ /text/ ){
      for( j = (NR<SZ ? k-NR : 0); j < k; j++ ) print A[j]
    }
  }
}

'text' is the pattern to match. Just change the LN variable to whatever number of lines to print before and after the line matched (and printed).

Cheers,
ND [smile]
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top