Home > front end >  Displaying and formatting specific lines before and after a match in Bash
Displaying and formatting specific lines before and after a match in Bash

Time:01-08

I am working with a file structured like this:

Title1
- Quote

this is a quote
==========
Title1
- Note

this is a note
==========
Title1
- Quote

this is another quote
==========
Title1
- Note

this is another note

Each Title (Title1 Title2..) contains hundreds of quotes and some of those quotes have notes following them. Each specific note and quote is exactly 1 line. For a given Title I want to display "this is a quote" followed by "this is a note":

this is a quote
   >> this is a note
--
this is another quote
   >> this is another note

I came up with something like this:

grep -C 6 "Title1" | grep -B 3 -A 2 "Note" | egrep -v "Title1|=====|Note"

I got this result :

this is a quote

this is a note
--
this is another quote

this is another note

How do I format the text to achieve the results above? I am still new to Bash and wondering if there's a more efficient way to achieve this? I was experimenting with sed for this but I couldn't get it to work. Any help would be highly appreciated!

Edit: I should have been clearer about this. I'd like to clarify that "this is a quote" and "this is a note" contain different strings each time, while "Quote" and "Note" are the same throughout the file.

CodePudding user response:

If using awk is an option:

awk -v title="Title1" '$0~title{f=1} /Quote/&&f==1{q=1} /Note/&&f==1{n=1} /====/{f=0;q=0;n=0} /^$/ && f==1 && q==1 {getline; print} /^$/ && f==1 && n==1 {getline; printf "%6s %s\n",">>",$0}' src.dat
this is a quote
    >> this is a note
this is another quote
    >> this is another note

-v title="Title1" pass the target title as a variable to awk

$0~title{f=1} set flag 'f' if current line matches target title.

/Quote/&&f==1{q=1} set quote flag 'q' if title flag is set and current line matches 'Quote'.

/Note/&&f==1{n=1} set note flag 'n' if title flag is set and current line matches 'Note'.

/^$/ && f==1 && q==1 {getline; print} if current line is empty and title and quote flags are set, get the next line and print.

/^$/ && f==1 && n==1 {getline; printf "%6s %s\n",">>",$0}'. if current line is empty and title and note flags are set, get the next line and print it as formatted output.

/====/{f=0;q=0;n=0} clear flags if current line matches '===='.

contents of src.dat file used for testing:

Title1
- Quote

this is a quote
==========
Title1
- Note

this is a note
==========
Title1
- Quote

this is another quote
==========
Title1
- Note

this is another note
  • Related