在文件中搜索关键字,然后使用perl或sed在正文中找到关键字后添加行

时间:2018-09-17 11:59:23

标签: perl awk sed

我试图在一个冗长的文件(input.txt)中搜索一个关键字(cell(edita)),该文件具有10000行以上的行以及不同的单元格名称,例如cell(noedit),cell(editb)。然后我应该搜索对于插针(q)(第二次出现)并添加行“ class”,插针(yz)(第二次出现)并添加“木板”。 我不应该操纵单元格(noedit)块

我的input.txt

        cell (edita)  {
            test{
                 pin (Q) {
                 zzzzzz
                }
                pin (yz) {
                zzzzz 
                }
                }
                 pin (Q) {
                 add
                 }
                 pin (yz) {
                 add 
             }
        }
        cell (noedit)  {
            test{
                 pin (Q) {
                 zzzzzz
                }
                pin (yz) {
                zzzzz 
                }
                }
                 pin (Q) {
                 add
                 }
                 pin (yz) {
                 add 
             }
        }
    cell (editb)  {
            test{
                 pin (Q) {
                 zzzzzz
                }
                pin (yz) {
                zzzzz 
                }
                }
                 pin (Q) {
                 add
                 }
                 pin (yz) {
                 add 
             }
        }

我的output.txt应该看起来像这样

cell (edita)  {
            test{
                 pin (Q) {
                 zzzzzz
                }
                pin (yz) {
                zzzzz 
                }
                }
                 pin (Q) {
                 "class";
                 add
                 }
                 pin (yz) {
                 board;
                 add 
             }
        }
        cell (noedit)  {
            test{
                 pin (Q) {
                 zzzzzz
                }
                pin (yz) {
                zzzzz 
                }
                }
                 pin (Q) {
                 add
                 }
                 pin (yz) {
                 add 
             }
        }
    cell (editb)  {
            test{
                 pin (Q) {
                 zzzzzz
                }
                pin (yz) {
                zzzzz 
                }
                }
                 pin (Q) {
                 "class";
                 add
                 }
                 pin (yz) {
                 board ;
                 add 
             }
        }

我尝试编写sed,仅当文件来自pin时(即,没有单元格(a)行),甚至只操纵第二次出现

sed'/\spin\s(Q)/{p;s/./1/;H;g;/^(\n1){2}$/s// class; / p; d}'input.txt sed'/\spin\s(y)/{p;s/./1/;H;g;/^(\n1){2}$/s//板; / p; d}'input.txt

请任何人帮我寻找细胞然后进行操纵。

预先感谢

4 个答案:

答案 0 :(得分:1)

关于perl的idk,但sed用于做s / old / new 全部,而对于其他任何标准UNIX工具来说,awk都是为了清晰,简单,高效,可移植性等。从您的示例中可以看出,这就是您要做的所有事情:

$ cat tst.awk
BEGIN {
    map["pin (Q)"] = "class ;"
    map["pin (y)"] = "board ;"
}
{ print }
$1 == "cell" { cell = "$2" }
cell == "(a)" {
    for (pin in map) {
        if ( (s=index($0,pin)) && (++cnt[pin]==2) ) {
            print substr($0,1,s-1) map[pin]
        }
    }
}

$ awk -f tst.awk file
cell (a)  {
    test{
         pin (Q) {
         zzzzzz
        }
        pin (y) {
        zzzzz
        }
        }
         pin (Q) {
         class ;
         add
         }
         pin (y) {
         board ;
         add
     }
}

如果不是,那么请编辑您的问题以阐明您的要求并提供更真实的示例输入输出。

从您在@potong答案下的评论中可以看到,您想添加第3个针脚-为此,您只需在现有2个map[]分配下添加新映射即可。

BEGIN {
    map["pin (Q)"] = "class ;"
    map["pin (y)"] = "board ;"
    map["pin (z)"] = "board2 ;"
}

答案 1 :(得分:0)

这可能对您有用(GNU sed):

sed '1{x;s/^/;,/;x};/^cell (a)/I,/^}/{/pin (q)/I{x;s/;/&q/;/;q\{2\},/{x;p;s/pin.*/class ;/;x};x};/pin (y)/I{x;s/,/&y/;/,y\{2\}$/{x;p;s/pin.*/board ;/;x};x}}' file

使用几个定界符(;的计数器pin (q),的计数器pin (y))分隔保留空间。将处理限制为cell (a)。每次遇到pin (q)pin (y)时,请在保留空间中为其相应的计数器添加一个。如果计数器为2(可以是任何数字),则打印当前行,然后修改当前行以反映附加的字符串。

编辑: 由于原始问题已更改:

sed '/cell ([^)]*)/{h;x;s/^/;:,/;x};G;/cell (edit[ab])/{/pin (q)/I{x;s/;/&q/;/;q\{2\}:/{x;P;s/\S.*/"class";/;x};x};/pin (yz)/I{x;s/:/&y/;/:y\{2\},/{x;P;s/\S.*/board/;x};x}};P;d' file

答案 2 :(得分:0)

Perl解决方案。这可以用作Unix过滤器。因此,如果它在名为transform的文件中,则应将其运行为:

$ transform < input.txt > output.txt

代码如下:

#!/usr/bin/perl

use strict;
use warnings;

my $in_cell_a;
my $brace_level = 0;
my ($pin_q, $pin_y);

while (<>) {
  print;
  if (/{/) {
    $brace_level++;
  }
  if (/cell \(a\)/) {
    $in_cell_a = $brace_level;
  }
  if (/(\s*)pin \(Q\)/) {
    if ($pin_q) {
      print "${1}class ;\n";
      $pin_q = 0;
    } else {
      $pin_q = 1;
    }
  }
  if (/(\s*)pin \(y\)/) {
    if ($pin_y) {
      print "${1}board ;\n";
      $pin_y = 0;
    } else {
      $pin_y = 1;
    }
  }

  if (/}/) {
    if ($brace_level == $in_cell_a) {
      $in_cell_a = 0;
    }
    $brace_level--;
  }
}

更新:这是使用更多数据驱动方法的更新版本。要添加额外的转换,您只需将其添加到$fix变量中即可。

#!/usr/bin/perl

use strict;
use warnings;

my $in_edit_block;
my $brace_level = 0;

my $fix = {
  'pin (Q)' => "class ;\n",
  'pin (y)' => "board ;\n",
};

my $flag;

my $fix_re = join '|', map { "\Q$_\E" } keys %$fix;

while (<>) {
  print;
  if (/{/) {
    $brace_level++;
  }
  if (/\Qcell (a)/) {
    $in_edit_block = $brace_level;
  }
  if ($in_edit_block) {
    if (my ($pad, $match) = /(\s*)($fix_re)/) {
      if ($flag->{$match}) {
        print "${pad}$fixes->{$match}";
        $flag->{$match} = 0;
      } else {
        $flag->{$match} = 1;
      }
    }
  }

  if (/}/) {
    if ($brace_level == $in_edit_block) {
      $in_edit_block = 0;
    }
    $brace_level--;
  }
}

答案 3 :(得分:0)

如果单元格(a)的块数超过1个...

awk '
  function addline(ind, value) {
    if(++a[ind]==2) { 
      b=$0
      sub(/[^[:blank:]].*/,"",b)
      $0=$0 "\n" b value " ;"
    }
  }
  /^cell/ {
    split("",a)
    f=0
    if(/(a)/)
      f=1
  }
  $0 ~ "pin [(]Q[)]" && f {
    addline("Q", "class")
  }
  $0 ~ "pin [(]y[)]" && f {
    addline("y", "board")
  }
1' input.txt