如何使用 sed 只打印文本报告文件中的特定“表”?

如何使用 sed 只打印文本报告文件中的特定“表”?

在 Quartus 生成的报告文件中,有多个“表”,如下所示:

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

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

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

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

注意:部分和表格之间始终有一个空行。

我希望能够根据与“表头”匹配的内容打印出一张完整的表格,如下所示。

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

我们目前使用 grep 的以下组合来打印起始表行和 sed 来打印其余部分,但看起来我应该能够仅使用 sed 来完成这一切。

grep -h -B 1 "; Table1 Header" quartus.rpt | grep -v "; Table1 Header"
sed -n '/; Table1 Header/,/^$/p' quartus.rpt

答案1

使用任何 awk:

$ awk -v RS= '/Table1 Header/' file
+-----------------+
; Table1 Header   ;
+--------+--------;
; Field1 ; Field2 ;
; Field3 ; Field4 ;
+--------+--------+
Table notes

答案2

Perl 的段落模式 ( -00) 对此很有用,它一次读取一个段落的输入(标准输入和/或文件)。段落是一直延伸到下一个空行的文本块 - 段落边界是一个或多个空行。

例如:

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

这将打印与模式“Table1 标题”匹配的任何段落 - 该模式是 perl 正则表达式,因此可以根据您的需要简单或复杂。man perlre详情请参阅。


顺便说一句,如果您想打印整个部分,而不仅仅是一张表,您可以执行以下操作:

$ 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 ;
+---------------+--------+

英文:如果当前段落与“Section”匹配,则如果段落与“Section1”匹配,变量 $match 将设置为 1,如果不匹配,则变量 $match 设置为 0。当 $match 计算结果为 true(非零)时打印任何段落。

这是另一个更通用的变体,如果文字字符串“Section”不是要匹配的模式的一部分,它可能会更有用:

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

这将打印从匹配“Section1”的段落开始到的每个段落,但不包括包含“Section2”的段落。即打印在“Section1”处打开,在“Section2”处关闭。

答案3

我的解决方案可能看起来比您希望的更加巴洛克,但它在 sed 中完成整个处理并生成您正在寻找的输出。

由于其复杂性,将其放入 sed 脚本中比希望在 bash 中使用 oneliner 更容易。

首先将以下内容放入一个文件中,我table-extract.sed在我的机器上调用该文件:

#! /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

使其可执行:chmod +x table-extract.sed

使用来自 OP 的 MWE 的输入运行示例:

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

希望脚本中的注释足够不言自明,特别是如果您有 sed 经验的话。基本上,sed 有保留空间与模式空间的概念。我使用保留空间来挂起“前一行”,直到找到匹配的标头名称,这样我们就可以将 保留+-------+在表的顶部。

找到并打印标题后,脚本跳到第二个循环,在退出之前打印表的其余部分。

答案4

您可以使用单个 sed 命令根据“表头”匹配打印出完整的表。以下命令将根据“Table1 Header”的匹配打印完整的表格,包括表格标题和注释:

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

此命令使用 sed 命令在“quartus.rpt”文件中搜索模式“Table1 Header”。 -n 选项禁止 sed 的默认输出,p 标志告诉 sed 仅打印与模式匹配的行。 ,/^$/ 部分告诉 sed 继续打印行,直到遇到空行(由 ^$ 正则表达式表示)。

相关内容