1

In a report file generated from Quartus, there are multiple "tables" like the following:

+---------------------+
; Section1 Title      ;
+---------------------+
Miscellaneous text

+-----------------+
; Table1 Header   ;
+--------+--------;
; Field1 ; Field2 ;
; Field3 ; Field4 ;
+--------+--------+
Table notes

+------------------------+
; Table2 Header          ;
+---------------+--------;
; Longer Field1 ; Field2 ;
; Longer Field3 ; Field4 ;
+---------------+--------+

+---------------------+
; Section2 Title      ;
+---------------------+
Miscellaneous text

NOTE: There is always a blank line between sections and tables.

I want to be able to print out just one full table like the following based on it matching the "Table Header".

+-----------------+
; Table1 Header   ;
+--------+--------;
; Field1 ; Field2 ;
; Field3 ; Field4 ;
+--------+--------+
Table notes

We currently use the following combination of a grep to print out the beginning table line and a sed to print the rest, but it seems like I should be able to do it all with just sed.

grep -h -B 1 "; Table1 Header" quartus.rpt | grep -v "; Table1 Header"
sed -n '/; Table1 Header/,/^$/p' quartus.rpt
JohnR
  • 13
  • 5
  • 1
    Is there any reason why you've restricted the question to `sed`? Any chance you could give a minimal example of input and expected output to match that input? At the moment there is only a fragment input and a verbal description of the output. This isn't quite clear enough to test an implementation, sorry. – cryptarch Jan 13 '23 at 22:03
  • 1
    I picked sed, just because we're already using it and I have experience with it. I don't need an optimal solution. I was just trying to simplify our existing solution. – JohnR Jan 13 '23 at 22:10
  • Fair enough. Thanks for the MWE. – cryptarch Jan 13 '23 at 22:16

4 Answers4

3

Using any awk:

$ awk -v RS= '/Table1 Header/' file
+-----------------+
; Table1 Header   ;
+--------+--------;
; Field1 ; Field2 ;
; Field3 ; Field4 ;
+--------+--------+
Table notes
Ed Morton
  • 28,789
  • 5
  • 20
  • 47
2

Perl's paragraph mode (-00) is good for this, it reads the input (stdin and/or file(s)) one paragraph at a time. A paragraph is a block of text extending until the next blank line - the paragraph boundary is one or more blank lines.

For example:

$ perl -00 -ne 'print if /Table1 Header/' quartus.rpt 
+-----------------+
; Table1 Header   ;
+--------+--------;
; Field1 ; Field2 ;
; Field3 ; Field4 ;
+--------+--------+
Table notes

That prints any paragraph matching the pattern "Table1 Header" - the pattern is a perl regular expression, so can be as simple or complicated as you need. See man perlre for details.


BTW, if you wanted to print an entire Section, rather than just one table, you could do something like:

$ perl -00 -ne 'if (/Section/) { $match = /Section1/ ? 1 : 0 }; print if $match' quartus.rpt
+---------------------+
; Section1 Title      ;
+---------------------+
Miscellaneous text

+-----------------+
; Table1 Header   ;
+--------+--------;
; Field1 ; Field2 ;
; Field3 ; Field4 ;
+--------+--------+
Table notes

+------------------------+
; Table2 Header          ;
+---------------+--------;
; Longer Field1 ; Field2 ;
; Longer Field3 ; Field4 ;
+---------------+--------+

In English: if the current paragraph matches "Section" then variable $match is set to 1 if the pargraph matches "Section1" or 0 if it doesn't. Print any paragraph when $match evaluates as true (non-zero).

Here's another more generic variant that might be more useful if the literal string "Section" isn't part of the pattern to match on:

$ perl -00 -ne '$match = 1 if /Section1/;
                $match = 0 if /Section2/;
                print if $match' quartus.rpt

This prints every paragraph starting from the paragraph matching "Section1" up to, but not including the paragraph containing "Section2". i.e. printing is toggled on at "Section1", and toggled off at "Section2".

cas
  • 1
  • 7
  • 119
  • 185
0

My solution perhaps looks a little more baroque than you were hoping for, but it does the entire processing in sed and generates the output you are looking for.

Due to the complexity, it is easier to put it into a sed script rather than hoping for a oneliner in bash.

First put the following into a file, which I called table-extract.sed on my machine:

#! /bin/sed -nf

# Label to loop back to after each line is checked
:search_for_table_start
# This stanza holds each line in case the next line is a matching header.
/; Table1 Header/!{
    h; n
}
# This stanza finds a matching header and prints it along with the preceding table delimiter.
/; Table1 Header/{
    x; p; x; p
    b search_for_table_end
}
# Go back to start of this loop
b search_for_table_start

# Label to loop back to while printing the rest of the table
:search_for_table_end
# This stanza gets and prints each line while we haven't found the end of the table yet.
/^$/!{
    n; p
}
# This stanza finds the end of the table and quits.
/^$/{
    q
}
# Go back to start of the print loop
b search_for_table_end

Make it executable: chmod +x table-extract.sed

Example run using the input from the OP's MWE:

$ ./table-extract.sed quartus.rpt
+-----------------+
; Table1 Header   ;
+--------+--------;
; Field1 ; Field2 ;
; Field3 ; Field4 ;
+--------+--------+
Table notes

Hopefully the comments in the script are self-explanatory enough, especially if you have sed experience. Basically, sed has a notion of hold space vs pattern space. I use hold space to hang onto "the previous line" until a matching header name is found, this way we preserve the +-------+ at the top of the table.

After finding and printing the header, the script skips to the second loop where the rest of the table is printed before exiting.

cryptarch
  • 1,255
  • 5
  • 23
-1

You can use a single sed command to print out the full table based on the "Table Header" match. The following command will print the full table, including the table header and notes, based on the match of "Table1 Header":

sed -n '/Table1 Header/,/^$/p' quartus.rpt

This command uses the sed command to search the "quartus.rpt" file for the pattern "Table1 Header". The -n option suppresses the default output of sed, and the p flag tells sed to print only the lines that match the pattern. The ,/^$/ part tells sed to continue printing lines until it encounters a blank line (indicated by the ^$ regular expression).

Mix tutor
  • 80
  • 6
  • This misses the leading `+------------+` at the top of the table – cryptarch Jan 13 '23 at 22:45
  • You can use the following command to include the leading line of the table: `sed -n '/; Table1 Header/,/^$/{/; Table1 Header/!p;}' quartus.rpt` This command also uses the "sed" command to search for the "Table1 Header" in the "quartus.rpt" file and the -n option to suppress the default output of sed. The curly braces {} enclose a set of commands that are executed for all lines matched by the address range '/; Table1 Header/,/^$/' . The command inside the curly braces /; Table1 Header/!p; will print all lines except the one matched with the pattern "; Table1 Header" – Mix tutor Jan 13 '23 at 22:51
  • This seems to be an answer from ChatGPT or something else. – Edgar Magallon Jan 14 '23 at 05:42
  • Maybe you are ChatGPT or something else :D – Mix tutor Jan 14 '23 at 14:16