Sed 从大型文本文件中剥离文本块

Sed 从大型文本文件中剥离文本块,sed,awk,Sed,Awk,我的任务很痛苦,我想知道是否有人能帮我 我们的供应商提供了一个SNMP mib文件(txt)。不幸的是,这个文件中有很多已经过时,需要在我们的监控应用程序中删除 我一直试图用手来做这件事,但它有超过80万行长,这正在削弱我的生存意志 结构类似于: -- /*********************************************************************************/ -- /* MIB table for Hardware

我的任务很痛苦,我想知道是否有人能帮我

我们的供应商提供了一个SNMP mib文件(txt)。不幸的是,这个文件中有很多已经过时,需要在我们的监控应用程序中删除

我一直试图用手来做这件事,但它有超过80万行长,这正在削弱我的生存意志

结构类似于:

-- /*********************************************************************************/
-- /* 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
    结束宏录制

  • 类型<代码>1000000@a(执行宏一百万次)


  • 我非常同意关于使用另一种脚本语言来解决这个问题的评论。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