4

I have a file structured like that:

BOF

-------Title1-------
stuff here
some stuff

-------Title2-------
extra things
extra things
extra things

-------Title3-------
and some stuff
   here

...

-------Title4-------
stuff

EOF

Now I would like to do something like this:

grep-by-section KEYWORD DELIMITER my-file

so that

grep-by-section "some" "^---" my-file

outputs

-------Title1-------
stuff here
some stuff

-------Title3-------
and some stuff
   here

I want to find a certain keyword and for every finding I want to output the whole block between known delimiters. How can I do that? sed fails me here.

Delimiters here are "------", but could be something else like numbers in [0-9]{8} format for example.

A similar problem which I couldn't solve is instead of outputting the contents of the block, output just the title of the block.

It seems to be easier to solve with perl than sed

ikegami
  • 367,544
  • 15
  • 269
  • 518
Strapakowsky
  • 2,313
  • 2
  • 16
  • 17
  • I think `awk` would be a good solution. See [this topic](http://stackoverflow.com/questions/15628017/) for a similar situation. – rojo Mar 30 '13 at 03:12

3 Answers3

4
#!/usr/bin/perl
my ($search, $del) = splice(@ARGV, 0, 2);
local $/;
while (<>) {
   for (/($del(?:(?!$del).)*)/smg) {
      print if /$search/sm;
   }
}

Notes:

  • local $/ causes the following readline to read a file at a time instead of a line at a time.
  • (?:(?!STRING).)* is to STRING as [^CHAR]* is to CHAR.
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • Wow. That is awesome, but can you make it more readable for us mortals? ;) (Hi ikegami!) – Jess Mar 30 '13 at 03:03
1

agrep can do this via: agrep -d DELIMITER KEYWORD FILE

jamesdlin
  • 81,374
  • 13
  • 159
  • 204
0

If there are true empty lines between those records, you would not need to use those delimiters, this would suffice:

awk '/KEYWORD/' RS= ORS='\n\n' file

Otherwise you could also try this awk:

awk '
  $0~key{
    f=1
  }
  $0~del{
    if(f)print s
    f=0
    s=$0
    next
  }
  {
    s=s RS $0
  }
  END{
    if(f)print s
  }
' key="KEYWORD" del="DELIMITER" file

In one line:

awk '$0~key{f=1} $0~del{ if(f)print s ; f=0; s=$0; next } {s=s RS $0} END{ if(f)print s }' key="KEYWORD" del="DELIMITER" file
Scrutinizer
  • 9,608
  • 1
  • 21
  • 22