Como extrair um campo particular de linhas de um arquivo, baseado em linhas subsequentes correspondentes

2

Estou tentando replicar um problema no local de trabalho. Eu tenho um arquivo xml como abaixo

[~]$ less -N sample.xml
  1     <SOURCE BUSINESSNAME ="" NAME ="TABLE1" FOO="ABCD"..... >
  2         <SOURCEFIELD BUSINESSNAME ="" NAME ="COL_XYZ" />
  3         <SOURCEFIELD BUSINESSNAME ="" NAME ="COL_ABCD" />
  4         ...
  5                 ...
  6     </SOURCE>
  7     <SOURCE BUSINESSNAME ="" NAME ="TABLE2" ....... >
  8             <SOURCEFIELD BUSINESSNAME ="" NAME ="COL_ABCD" />
  9         <SOURCEFIELD BUSINESSNAME ="" NAME ="COL_XYZABC" />    
 10         ...
 11                 ...
 12     </SOURCE>
 13         <SOURCE BUSINESSNAME ="" NAME ="TABLE3" .... >
 14         <SOURCEFIELD BUSINESSNAME ="" NAME ="COL_PQR" />
 15         <SOURCEFIELD BUSINESSNAME ="" NAME ="COL_ABCD" />
 16         ...
 17                 ...
 18     </SOURCE>

Agora, quero o valor do campo NAME , em que qualquer SOURCEFIELD NAME é igual a XYZ .

Por exemplo, no exemplo fornecido, eu preciso de TABLE1 , pois a linha 2 contém COL_XYZ . E também TABLE2 como na linha 9 , temos COL_XYZABC

Eu estava pensando de alguma forma, para obter a linha 1,2,7,9,13 como saída e, em seguida, o campo grep -B1 XYZ|grep -w SOURCE para obter apenas a linha 1,7 na saída.

Expected Output:
TABLE1
TABLE2

O que eu tentei até agora

  • Fazer um grep no SOURCE não está funcionando, pois cada linha tem pelo menos um deles.
  • Fazer egrep -w "SOURCE|XYZ" não está funcionando, pois eu preciso que XYZABC não satisfaça sua condição.

Alguém poderia sugerir algo que eu possa tentar obter o resultado desejado? Estou usando Linux 2.6.18-371.el5

    
por Utsav 14.12.2015 / 12:22

3 respostas

2

Você pode fazer isso usando o recurso hold space de sed .

Execute sed com a opção -n para suprimir a impressão automática de linhas de entrada.

Quando a linha contendo <SOURCE for vista, salve o valor do atributo NAME em sed ' hold space .

Quando a linha <SOURCEFIELD contendo XYZ for vista, imprima o conteúdo do hold space .

#!/bin/sh

sed -n '
    /<SOURCE / {              # execute block {} on lines matching "<SOURCE "
        s/.* NAME *="//       # remove everything upto NAME attribute value
        s/".*//               # remove everything after attribute value
        h                     # copy pattern space to the hold space
    }
    /<SOURCEFIELD.*XYZ/ {     # SOURCEFIELD contains XYZ, execute {} block
        g                     # copy hold space to pattern space
        p                     # print
    }
' "$@"
    
por 14.12.2015 / 12:43
1
sed -netP -eH            -e'# Hold every line and test for s///uccess' \
    -e'\|<[^F]*[ >]|!d'  -e'# if < then F before [ >]: delete'         \
-ex -e'\|_XYZ[^_]*>|!d'  -e'# first exchange buffers; if !XYZ: delete' \
    -e's|[^"]*|\n&\n|4'  -e'# wrap 4th no quotes series in newlines'   \
    -e'D;:P' -eP         -e'# Delete up to first newline, :Print if true'
TABLE1
TABLE2

... e quando adiciono um XYZ ao último campo da terceira lista, TABLE3 imprime também ...

    
por 14.12.2015 / 18:13
0

Graças a RobertL para este responder .

Eu também criei uma combinação de grep/awk/sed para conseguir o mesmo, mas é mais lento, obviamente. Só queria colocar isso lá fora.

egrep -w ""\<SOURCE"|"SOURCEFIELD.*XYZ.*"" sample.xml|grep -B1 XYZ|grep -w SOURCE|\                                                              
> awk -F" NAME =" '{print $2}'|awk '{print $1}'|sed 's/"//g'
    
por 14.12.2015 / 13:57