Sed 从大型文本文件中剥离文本块
我的任务很痛苦,我想知道是否有人能帮我 我们的供应商提供了一个SNMP mib文件(txt)。不幸的是,这个文件中有很多已经过时,需要在我们的监控应用程序中删除 我一直试图用手来做这件事,但它有超过80万行长,这正在削弱我的生存意志 结构类似于:Sed 从大型文本文件中剥离文本块,sed,awk,Sed,Awk,我的任务很痛苦,我想知道是否有人能帮我 我们的供应商提供了一个SNMP mib文件(txt)。不幸的是,这个文件中有很多已经过时,需要在我们的监控应用程序中删除 我一直试图用手来做这件事,但它有超过80万行长,这正在削弱我的生存意志 结构类似于: -- /*********************************************************************************/ -- /* MIB table for Hardware
-- /*********************************************************************************/
-- /* MIB table for Hardware */
-- /* Valid from: 543.44 */
-- /* Deprecated from: 600.3 */
-- /*********************************************************************************/
Some text
some text
Some text
-- /*********************************************************************************/
-- /* MIB table for Hardware */
-- /* Valid from: 543.44 */
-- /*********************************************************************************/
Some text
some text
Some text
-- /*********************************************************************************/
-- /* MIB table for Hardware */
-- /* Valid from: 364.44 */
-- /* Deprecated from: 594.3 */
-- /*********************************************************************************/
随意重复,毫无生气
我所想的是一个脚本,它将:
查找文本“已弃用自”
然后
这有意义吗?这是可能的,还是我只是在做梦
谢谢 编辑:我刚刚意识到我看错了你的问题,即使是在经过几次投票之后。我之前的回答是错的!现在应该更正确了,但需要一些额外的假设。简单的解决方案只能让你走这么远 通过以下几个假设,这可能会对您有所帮助:
cat -s data | awk -vFS='\n' -vRS='\n\n' '/Deprecated from/ { getline; next } 1'
cat
命令只是用来挤出多余的换行符,因此awk
可以更容易地操作。至于awk
,-vFS='\n'
告诉它字段由换行符分隔,而-vRS='\n\n'
告诉它记录由一行中的两个换行符分隔。然后/Deprecated from/
查找包含该文本的记录,并{getline;next}
读入该文本之后的下一条记录,并使其继续移动1
是打印到达以下点的行的快捷方式
这将假定以下情况:
- 所有注释和文本块在两侧至少用一个空行分隔
- 只有注释块和文本块均匀分布
- 文本块中没有空行
awk
成为这项工作的一个不错的选择,正如您所看到的:脚本非常小
$ cat -s data | awk -vFS='\n' -vRS='\n\n' '/Deprecated from/ { getline; next } 1'
-- /*********************************************************************************/
-- /* MIB table for Hardware */
-- /* Valid from: 543.44 */
-- /*********************************************************************************/
Some text
some text
Some text
此外,正如您所看到的,保留的新行被挤出。为此,您可以修改如下命令:
$ cat -s data | awk -vFS='\n' -vRS='\n\n' '/Deprecated from/ { getline; next } { printf "%s\n\n", $0 }'
-- /*********************************************************************************/
-- /* MIB table for Hardware */
-- /* Valid from: 543.44 */
-- /*********************************************************************************/
Some text
some text
Some text
这是一个简单的
vim
宏
$vim filename
q a
在寄存器a
/Deprecated from:
,后跟Enter(搜索文本)3k
(上升3行)4dd
(删除此行和下一行)d/\*\*\*\*\*\*
(删除splats之前的行)dd
(删除当前行)q
结束宏录制我非常同意关于使用另一种脚本语言来解决这个问题的评论。Ruby、Perl或Python可能会更好。但为了好玩,这里有一个丑陋的Awk脚本。如果不合适的话,比赛可能需要一些技巧。但是is实现了一个简单的状态机。它跟踪它是否在标题中,并确定它是否已弃用。它将标题行存储在一个数组中。当它到达标题的末尾时,它将打印标题(如果没有弃用)。当不在标题中时,如果前一节未被弃用,它将打印行
{
if ( $0 ~ /-- \/\**+\// ) {
# This matches one of the -- /*********...****/ lines
if ( headercount > 0 ) {
# this must be the closing line in the header
if ( !deprecated ) {
for ( i = 0; i < headercount; i++ ) {
print headers[i]
}
# print closing line
print
} # if not deprecated
headercount = 0
}
else {
# must be starting a new section
headers[0] = $0
headercount = 1
deprecated = 0
}
}
else {
if ( headercount == 0 ) {
# not in a header section - print if not deprecated
if ( !deprecated ) {
print
}
}
else {
# in a header section - track if it is a deprecated section
if ( $0 ~ /Deprecated from/ ) {
deprecated = 1
}
# store the header info to dump when we hit the end
headers[headercount++] = $0;
}
}
}
{
如果($0~/--\/\***+\//){
#这与其中一个--/*********…***/行匹配
如果(表头计数>0){
#这必须是标题中的结束行
如果(!已弃用){
对于(i=0;i
这可能适合您:
sed '$!N;$!N;:a;$q;N;/Deprecated from/!{P;s/^[^\n]*\n//;ba};$d;$!N;$d;s/.*//;:b;$d;N;/^\n-- \/\*\+\/$/!{s/.*//;bb};D' file
这里有一个稍微简单的解决方案(效率较低,因为它需要两个过程):
从
不推荐的
中删除到/**…
是相当容易的,删除前面的3行有点困难。我认为用sed或awk处理这件事会削弱我的生存意志。对于这个问题,Perl或其他一些允许您围绕行边界进行解析的语言是一个更好的选择。我非常希望它能够工作,但对我来说不行。我什么也没印出来。@DanFego哎呀!在中留下了调试帮助。删除它,再试一次。这是一堆乱七八糟的字母和符号,但对我来说很有用!
sed '$!N;$!N;:a;$q;N;/Deprecated from/!{P;s/^[^\n]*\n//;ba};$d;$!N;$d;s/.*//;:b;$d;N;/^\n-- \/\*\+\/$/!{s/.*//;bb};D' file
awk '/Deprecated from/{a=NR-3;getline;next};a>0 && /^-- \/\*+\/$/{b=NR-1;print a "," b "d";a=b=0};END{if(a>0)print a ",$d"}' file |
sed -f - file