expressão regular combina texto em chaves e imprime chaves inteiras

1

Eu tenho arquivo de configuração como:

define host{
        host_name xxxxxxxx1748
        use windows-server
        alias Comet
        hostgroups +bu-automotiveprd,screen-automotiveprd2
        address XXX.XXX.XXX.XXX
}


define host{
        host_name yyyyyyyyy991
        use aix-server
        alias
        hostgroups +bu-automotiveprd,screen-automotiveprd2
        address YYY.YYY.YYY.YYY
}

Gostaria de pesquisar host_name e, se estiver correspondendo, a saída deve estar como abaixo:

Exemplo - suponhamos que eu queira pesquisar yyyyyyyyy991 host.

Em seguida, a saída deve ser como abaixo:

define host{
        host_name yyyyyyyyy991
        use aix-server
        alias
        hostgroups +bu-automotiveprd,screen-automotiveprd2
        address YYY.YYY.YYY.YYY
}
    
por Rakesh Kumar 24.09.2018 / 09:55

4 respostas

0

Usando sed :

sed 'H;/^define host{$/h;/^}/{g;/host_name yyyyyyyyy991\n/p};d' file

Passo-a-passo:

H                  # append line to hold space
/^define host{$/h  # start of entry: copy to hold space (overwrites previous content)
/^}/{              # end of entry:
        g                            # retrieve whole entry from hold space
        /host_name yyyyyyyyy991\n/p  # if host matched, display the whole entry
}
d                  # no other output
    
por 24.09.2018 / 11:50
3

tente isso,

perl -0777 -ne '/([^\n]*{[^}]*(yyyyyyyyy991)[^}]*})/ && print "$1\n"' file

Explicação:

  • perl -0777 Execute perl e faça slurp no arquivo inteiro como uma linha.
  • -ne para cada linha ( n ), execute ( e ) o seguinte.
  • /(pattern)/ && print "$1\n" corresponde a um padrão de expressão regular e adiciona-o como primeiro grupo correspondente ( $1 ) e, em seguida, imprime-o.

O padrão:

  • [^\n]*{ ... } Combine qualquer coisa desde o começo de uma linha, incluindo "{" até o próximo "}"
  • Com o ... sendo [^}]*(yyyyyyyyy991)[^}]* :
    • Corresponda qualquer caractere que não seja }
    • deve incluir yyyyyyyyy991 em algum lugar.
por 24.09.2018 / 10:36
2

Se o seu grep for compatível, você poderá usar a opção -z para fazer com que o arquivo inteiro seja sugado:

$ grep -ozE 'define[^}]*host_name yyyyyyyyy991.+?}.' file
define host{
        host_name yyyyyyyyy991
        use aix-server
        alias
        hostgroups +bu-automotiveprd,screen-automotiveprd2
        address YYY.YYY.YYY.YYY
}

As opções grep usadas são (da página man do GNU grep ):

  -z, --null-data
          Treat  input  and output data as sequences of lines, each terminated by a
          zero byte (the ASCII NUL character) instead of a newline.  Like the -Z or
          --null  option,  this  option  can  be used with commands like sort -z to
          process arbitrary file names.
  -o, --only-matching
          Print only the matched (non-empty) parts of a matching  line,  with  each
          such part on a separate output line.
  -E, --extended-regexp
          Interpret PATTERN as an extended regular expression (ERE, see below).

A expressão regular procura a palavra define , seguida por 0 ou mais caracteres que não } ( [^}]* ), depois host_name yyyyyyyyy991 e depois tudo até o primeiro } ( .+? ) mais o próximo caractere (o final . ) que corresponderá à nova linha.

Pessoalmente, no entanto, eu faria esse tipo de coisa usando o modo de parágrafo do perl:

$ perl -00 -ne 'print if /yyyyyyyyy991/' file
define host{
        host_name yyyyyyyyy991
        use aix-server
        alias
        hostgroups +bu-automotiveprd,screen-automotiveprd2
        address YYY.YYY.YYY.YYY
}

O -00 informa perl para ler o arquivo de entrada como parágrafos, portanto cada registro é um parágrafo (definido por 2 caracteres \n consecutivos) em vez de uma linha. Então, o -ne significa "Leia cada registro de entrada e aplique o script dado por -e a ele". O próprio script simplesmente imprime todos os registros correspondentes ao padrão desejado.

    
por 24.09.2018 / 10:40
2

Digamos que seu arquivo de configuração seja chamado de config.dat e tenha o formato padrão . O que significa que você só tem uma linha antes de yyyyyyyyy991 e cinco linhas depois dela, então este comando irá ajudá-lo a obter a saída desejada:

grep -B 1 -A 5 "yyyyyyyyy991" config.dat

define host{
        host_name yyyyyyyyy991
        use aix-server
        alias
        hostgroups +bu-automotiveprd,screen-automotiveprd2
        address YYY.YYY.YYY.YYY
}

Em grep man :

Context control flage:
  -B, --before-context=NUM  print NUM lines of leading context
  -A, --after-context=NUM   print NUM lines of trailing context

Outra solução caso o arquivo config.dat não seja padrão , significando que a palavra chave "yyyyyyyyy991" não segue o mesmo padrão em todas as seções, então awk pode fazer o que você quiser da seguinte forma:

 awk -v RS='' '/host_name yyyyyyyyy991/' config.dat

RS = altera o separador de registro de entrada de uma nova linha para linhas em branco. Se algum campo em um registro contiver / host_name yyyyyyyyy991 / imprima o registro.

De acordo com o posix

Se RS é nulo, então os registros são separados por sequências que consistem em mais uma ou mais linhas em branco, linhas em branco iniciais ou finais não devem resultar em registros vazios no início ou no final da entrada, e um deve ser sempre um separador de campo, não importa qual seja o valor do FS.

Os parágrafos de saída não serão separados, pois o separador de saída permanece como uma nova linha. Para garantir que haja uma linha em branco entre os parágrafos de saída, defina o separador de registro de saída como duas novas linhas.

    
por 24.09.2018 / 10:29