Sed,awk或perl用于捕获2种模式之间的线条

时间:2013-11-21 16:07:10

标签: regex perl sed awk grep

我有一个文件格式如下:

pool1 {
  name:$NAME
  mode:$MODE
  address:$ADDRESS
  validity:$VALIDITY
     }

pool2 {
  name:$NAME
  mode:$MODE
  address:$ADDRESS
  validity:$VALIDITY
     }


pool3 {
  name:$NAME
  mode:$MODE
  version:$VERSION
  address:$ADDRESS
  validity:$VALIDITY
     }

我在另一个文件中有一个地址列表。虽然我遍历地址文件,但我需要在此文件中找到相应地址的名称。问题是池中的参数数量不固定,保持变化,如池3中显而易见的,其中一个名为version的新参数弹出.Hence我不能为地址执行正常的grep然后再次grep它上面的2行。我需要的是一个将搜索该事件的命令行“address:$ ADDRESS”,然后找到它之前发生的“name:$ NAME”..

4 个答案:

答案 0 :(得分:2)

这是你要找的吗?

$ cat file
pool1 {
  name:abc
  mode:$MODE
  address:foo
  validity:$VALIDITY
     }

pool2 {
  name:defghi
  mode:$MODE
  address:stuff
  validity:$VALIDITY
     }


pool3 {
  name:some other name
  mode:$MODE
  version:$VERSION
  address:bar
  validity:$VALIDITY
     }
$
$ cat tst.awk
BEGIN { RS=""; FS="\n" }
{
    split("",name2val)          # or delete(name2val) with gawk
    for (i=1;i<=NF;i++) {
        line = $i
        gsub(/^[[:space:]]+|[[:space:]]+$/,"",line)
        if ( split(line,tmp,/:/) == 2 ) {
            name2val[tmp[1]] = tmp[2]
        }
    }

    if ( name2val["address"] == tgt ) {
        print name2val["name"]
    }
}
$
$ awk -v tgt="stuff" -f tst.awk file
defghi

如果没有使用更好的示例和预期输出更新您的问题。

答案 1 :(得分:1)

您可以将范围模式与awk一起使用,并且如果name匹配,则在每个范围内打印address。当然可以使用-v

通过命令行传递地址
awk -vaddress=address3 '/pool.*\{/,/\}/{if ($0 ~ /name/)name=$0; 
    if($0 ~ address) print name}' file.txt

答案 2 :(得分:1)

这可能会让你开始:

#!/usr/bin/perl
use warnings;
use strict; 
use Data::Dumper;
$Data::Dumper::Sortkeys = 1;


my $infile = 'in.txt';
open my $input, '<', $infile or die "Can't open to $infile: $!";

my (@pool, @address, @name, %hash);
while (<$input>){
    chomp;
    push @pool, $1 if ($_ =~ /(pool\d+)\s+\{/g);
    push @address, $1 if ($_ =~ /address:(.+)/g);
    push @name, $1 if ($_ =~ /name:(.+)/g);
}

push @{$hash{$pool[$_]} }, [$address[$_], $name[$_] ] for 0 .. $#pool;

print Dumper \%hash;

它为您提供了数组的哈希:

$VAR1 = {
          'pool1' => [
                       [
                         '$ADDRESS',
                         '$NAME'
                       ]
                     ],
          'pool2' => [
                       [
                         '$ADDRESS',
                         '$NAME'
                       ]
                     ],
          'pool3' => [
                       [
                         '$ADDRESS',
                         '$NAME'
                       ]
                     ]
        };

现在,您可以读入包含地址的文件,并检查它们是否存在于上面的哈希

答案 3 :(得分:1)

似乎一个好的开始就是打印你感兴趣的游泳池,这对于awk来说是微不足道的。例如:

awk '/\n  address:pattern/' RS= input-file

只会打印地址与pattern匹配的池。通过将RS设置为空字符串,awk将段落(由空行分隔的文本块)视为单个记录。在理想的世界中,awk将该记录重新分析为字典并打印名称会很简单,但将输出传递给另一个awk非常简单:

awk '/\n  address:pattern/' RS= input-file | awk '/^  name/'