![如何使用 sed 只打印文本报告文件中的特定“表”?](https://linux22.com/image/215607/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8%20sed%20%E5%8F%AA%E6%89%93%E5%8D%B0%E6%96%87%E6%9C%AC%E6%8A%A5%E5%91%8A%E6%96%87%E4%BB%B6%E4%B8%AD%E7%9A%84%E7%89%B9%E5%AE%9A%E2%80%9C%E8%A1%A8%E2%80%9D%EF%BC%9F%20.png)
在 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 继续打印行,直到遇到空行(由 ^$ 正则表达式表示)。