Encontre padrão entre caracteres especiais

1

Eu preciso de um comando Sed / awk para imprimir os dados entre caracteres especiais, desde que a correspondência de padrões seja apresentada entre caracteres especiais ({&})

Eu tenho um arquivo que contém

define service {
host_name                       dns_vips
service_description             Multi Lookup 
use                             standard_service_template
active_checks_enabled           1
passive_checks_enabled          1
notifications_enabled           1
contact_groups                  mailgrp
max_check_attempts              3
normal_check_interval           5
retry_check_interval            1
notification_interval           10
check_period                    24x7
notification_period             24x7
notification_options            w,r,c
}
define service {
host_name                       dns_vips1
service_description             Multi Lookup 2  
use                             standard_service_template
active_checks_enabled           1
passive_checks_enabled          1
notifications_enabled           1
contact_groups                  mailgrp1
max_check_attempts              3
normal_check_interval           5
retry_check_interval            1
notification_interval           10
check_period                    24x7
notification_period             24x7
notification_options            w,r,c
}

Eu preciso de dados entre { e } quando a descrição do serviço corresponde à pesquisa múltipla

    
por harish 16.10.2015 / 10:46

4 respostas

3
sed '
    /{/{            #starts next code block if line include «{» 
        :1          #set mark point 
        /}/!{       #execute if pattern (collected lines) do not include «}»
            N       #add next line to the pattern space
            b1      #return to marked point
            }       #end of second (inner) block of code
        }           #end of first block of code 
    /Multi Lookup/p #prints pattern (collected lines) if it has «Multi Lookup»
    d               #clean pattern (start from the beginning)
' file
    
por 16.10.2015 / 11:33
1

Apenas por diversão, tentei fazer isso como vim one-liner. (Quem já ouviu falar de tal coisa, certo?)

vim -c 'g/service_description\s\+Multi Lookup\s\+$/?{?+,/}/-w! >> outputfile.txt' -c 'q!' inputfile.txt

O que isso faz: localiza cada linha que contém service_description [espaço em branco] Multi Lookup [espaço em branco, fim de linha] e exibe todas as linhas do{ anterior para as seguintes } para cada correspondência. não incluindo as linhas contendo os caracteres { e } e gravando as linhas de saída em outputfile.txt . Em seguida, sai sem modificar inputfile.txt .

Eu não sabia se você queria que Multi Lookup 2 correspondesse; Nesse caso, remova o \s\+$ após Multi Lookup .

Se você quiser incluir as linhas com as chaves também, remova o + após o ?{? e o - após o /}/ .

Provavelmente um exagero, já que você pode usar apenas sed , mas foi uma boa prática para mim. :)

    
por 16.10.2015 / 13:04
1

Isto é bastante simples com, e. perl se for uma opção. Analise o registro em pares de valores-chave e, em seguida, extraia / combine o campo desejado:

#!/usr/bin/env perl
use strict;
use warnings;

use Data::Dumper;

#set record separator to 'end bracket'. 
local $/ = '}';

#iterate our data based on that delimiter. 
#note - <> is a magic filehandle, in that it reads either pipe
#from stdin, or a file argument specified on command like (e.g. like awk/sed)
while (<>) {
    #extract key-value pairs with a multi line regex for this 'block'
    my %fields = m/(\w+)\s+(.*)$/gm;

    print Dumper \%fields; #to see what we captured for debugging. 

    #test a particular field against a regex. Note - this matches 
    #both in your example. 
    if ( $fields{service_description} =~ m/Multi Lookup/ ) {
        print "This record matches\n";
    }
}

Cada registro acima é colocado em campos e é um perl hash contendo:

$VAR1 = {
          'define' => 'service {',
          'use' => 'standard_service_template',
          'check_period' => '24x7',
          'host_name' => 'dns_vips',
          'service_description' => 'Multi Lookup ',
          'active_checks_enabled' => '1',
          'passive_checks_enabled' => '1',
          'notification_interval' => '10',
          'notification_period' => '24x7',
          'contact_groups' => 'mailgrp',
          'max_check_attempts' => '3',
          'notifications_enabled' => '1',
          'notification_options' => 'w,r,c',
          'normal_check_interval' => '5',
          'retry_check_interval' => '1'
        };

Isso pode ser compactado em um único liner, se desejado, mas tenho que ser um pouco mais específico sobre o que você está realmente querendo como saída.

por exemplo.

 perl -ne 'BEGIN { $/ = "}" } %f = m/(\w+)\s+(.*)$/gm; print if $f{service_description} =~ m/Multi Lookup/'

Ou talvez ainda mais simples:

perl -ne 'BEGIN { $/ = "}" } print if m/service_description.*Multi Lookup/'
    
por 16.10.2015 / 11:25
1

Se eu entendi corretamente, todos os seus dados estão dentro de { } e você deseja imprimir os registros cujo service_description corresponde a Multi Lookup . Nesse caso, você pode usar um truque legal perl .

Perl tem um "modo de parágrafo" onde os registros (linhas) são definidos por linhas em branco. Então, se você adicionar um caractere de nova linha após cada } , você pode simplesmente fazer:

sed 's/}/}\n/' file | perl -00ne '/service_description\s*Multi Lookup/ && print'

O sed adiciona \n após cada } . O -00 de Perl ativará o modo de parágrafo e -ne fará com que ele leia cada linha de entrada (aqui, linha significa parágrafo) e aplicará o script fornecido por -e a ele. O resultado é que os registros cuja service_description corresponde a Multi Lookup são impressos.

Como alternativa, você pode definir o separador de registros do perl (o que define uma "linha"), a variável $/ , no próprio script e evitar a sed step

perl -ne 'BEGIN{$/="}\n"}/service_description\s*Multi Lookup/ && print' file
    
por 16.10.2015 / 12:41