• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 485
  • Last Modified:

Using sed to match a pattern and then return the matched line as well as select lines above it.

Hello, I would like to use sed to search a file for a pattern (word) and then return the line containing that word, as well as the previous 3 lines.

For example, below is my sample file:

Apples are red
Oranges are orange
Pears are green
Bananas are yellow
Turnips are purple
Potatoes are brown

I would like to now search for the work Turnips and the command return the line containing Turnips as well as the previous 3 lines.

So, my output would look like below:

Oranges are orange
Pears are green
Bananas are yellow
Turnips are purple

I have searched sed websites and the closest I can come to the commanded needed is below. But, the below command excludes the line containing the match and I want the command to not only print the previous 4 lines, but also print the line containing the pattern.

#Print the line immediately after a regexp, but not the line
#Containing the regexp
 sed -n '/regexp/{n;p;}'

1.     So I created a sample file (below):

ibm05:/home/root (707)#cat sample_file    
Apples are red
Oranges are orange
Pears are green
Bananas are yellow
Turnips are purple
Potatoes are brown

2.     Then I modified the above command and here is what I get:

ibm05:/home/root (710)#sed -n '/Bananas/{g;1!p;};h' ./sample_file

ibm05:/home/root (711)#

All I get is a blank line. Any help that can be provided will be much appreciated, thanks.
0
shanetexas
Asked:
shanetexas
  • 4
  • 3
  • 3
  • +3
1 Solution
 
HamdyHassanCommented:
is this should be in sed ?
Is this homework ?
0
 
shanetexasAuthor Commented:
No. I'm trying to create a report for my work out of a large output file. Is there another was to accomplish this other than sed?
0
 
HamdyHassanCommented:
yes using perl script

---------------------
source code
---------------------

#!/usr/bin/perl

#----------------------
# Define input file
#----------------------
$sourceFile="ss.txt";

#---------------------------------------------------
# Define output files
#---------------------------------------------------
$DATAFile="ss.out";

#----------------------
# Create File Handlers
#----------------------
open(IN,"$sourceFile");
open(OUTA,">$DATAFile");

$l1="";
$l2="";
$l3="";

while ($myline=<IN>){
   if ($myline =~ /Potatoes/)
   {
     print OUTA $l3 ;
     print OUTA $l2 ;
     print OUTA $l1 ;
     print OUTA $myline ;
   }
   $l3=$l2;
   $l2=$l1;
   $l1=$myline;
}
close(IN);
close(OUTA);


-------------
input file
-------------
2733 bin/ee> cat ss.txt
Apples are red
Oranges are orange
Pears are green
Bananas are yellow
Turnips are purple
Potatoes are brown


-------------
output file
-------------
2734 bin/ee> cat ss.out
Pears are green
Bananas are yellow
Turnips are purple
Potatoes are brown
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
shanetexasAuthor Commented:
Is there a less complex way with sed?
0
 
HamdyHassanCommented:
It should be easy also with AWK
0
 
shanetexasAuthor Commented:
How would I do it with awk?
0
 
ecwCommented:
Trivially in awk ...

awk -v pattern="$pattern" 'BEGIN {
            prev1 = prev2 = prev3 = "";
}
{ if ($0 ~ pattern) print prev1 "\n" prev2 "\n" prev3 "\n" $0;
}
{ prev1 = prev2 ; prev2 = prev3 ; prev3 = $0 }
}' file

There are more elegant methods, but this should suffice, although it might output some spurious blank lines.
0
 
shanetexasAuthor Commented:
The awk script provided did not work. Here is the output it produced (I put the awk script into a file names shane2):

tech2:/home/root (695)#shane2          



Apples are red


Apples are red
Oranges are orange

Apples are red
Oranges are orange
Pears are green
Apples are red
Oranges are orange
Pears are green
Bananas are yellow
Oranges are orange
Pears are green
Bananas are yellow
Turnips are purple
Pears are green
Bananas are yellow
Turnips are purple
Potatoes are brown
0
 
TintinCommented:
Depends what flavour Unix you have or if you have GNU grep.

If so, then it is simple:

grep -B 3 Turnips sample.txt
0
 
ecwCommented:
Looks like you're searching for blank pattern, in whch case every line will match.
The gist of the awk script is to put in shell var pattern the word you're searching for.
ie.
 pattern=yellow
and then the awk stuff.

So to turn it into a full script, with a little bit more intelligence,

#!/bin/sh

awk -v pattern="$1"
shift
awk -v pattern="$pattern" 'BEGIN {
 lines[1] = line[2] = line[3] = ""
}
{ if ($0 ~ pattern) {
   if (NR > 3) {
     for (i = 1; i <= 3; ++i) print lines[i];
   } else {
     for (i = 1; i <= NR; ++i) print lines[i];
   }
   print $0;
  }
}
{ line[1] = line[2] ; line[2] = line[3] ; line[3] = $0 }
}' ${1+"$@"}
0
 
ecwCommented:
whoops, line shouldn't be
 awk -v pattern="$1"
should be
 pattern="$1"
0
 
prady_21Commented:
Well if the file size isnt too big, then you can try this

#!/usr/bin/perl

$filehandle = "/home/somewhere/some.txt";
open ( FILE, "$filehandle");
@lines =reverse <FILE>;
for $i ( 0 .. $#lines ) {
   if ( $lines[$i] =~ /Turnip/g) {
      @array_line = @lines[$i,$i+1,$i+2,$i+3];
      print "@array_line";
   }
}
exit 0;

0
 
liddlerCommented:
No comment has been added lately, so it's time to clean up this TA.
I will leave a recommendation in the Cleanup topic area that this question is:

Answered by ecw

Please leave any comments here within the next seven days.

PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER!

liddler
EE Cleanup Volunteer
0

Featured Post

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

  • 4
  • 3
  • 3
  • +3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now