br: extrai linhas até um padrão incomparável

2

Estou tentando extrair linhas de um arquivo em que a string final é diferente da string inicial

Eu tenho o seguinte arquivo de entrada em formato:

<item_id>6</item_id>
  <info1>abc</info1>
  <info2>123</info2>
<item_id>6</item_id>
  <info1>def</info1>
  <info2>456</info2>
<item_id>6</item_id>
  <info1>ghi</info1>
  <info2>789</info2>
<item_id>9</item_id> 
  <info1>jkl</info1>
  <info2>012</info2>
<item_id>9</item_id>
  <info1>mno</info1>
  <info2>345</info2>

Eu quero extrair de "6" até "9" (9 sendo um número aleatório)

Começar é <item_id>6<\item_id>

O final é <item_id>X<\item_id> X sendo tudo menos 6

Resultado esperado:

<item_id>6</item_id>
  <info1>abc</info1>
  <info2>123</info2>
<item_id>6</item_id>
  <info1>def</info1>
  <info2>456</info2>
<item_id>6</item_id>
  <info1>ghi</info1>
  <info2>789</info2>

Eu tentei:

sed -n "/<item_id>6<\/item_id>/,/<item_id>!6<\/item_id>/p" input.file > output.6
sed -n "/<item_id>6<\/item_id>/,/<item_id>\!6<\/item_id>/p" input.file > output.6
sed -n "/<item_id>6<\/item_id>/,/<item_id>\{!6}<\/item_id>/p" input.file > output.6
sed -n "/<item_id>6<\/item_id>/,/<item_id>(6)\@!.<\/item_id>/p" input.file > output.6
sed -n "/<item_id>6<\/item_id>/,/<item_id>! 6<\/item_id>/p" input.file > output.6
    
por xavi 10.11.2018 / 21:05

2 respostas

3

Talvez este script sed GNU funcione para você:

sed '/<item_id>6<\/item_id>/{:1;n;/<item_id>[^6]<\/item_id>/{Q};b1};d' file

Continue excluindo d linhas até encontrar uma linha 6 e, em seguida, mantenha o loop interno b1 imprimindo cada linha até que uma linha not 6 ([^ 6]) seja encontrada, quando o script é Q uit.

Entenda que isso funciona apenas para números de um caractere (o 6 ou o 9 ).

Fica um pouco confuso para que funcione com qualquer número (GNU):

sed -e 'h;s,<item_id>\([0-9]*\)<\/item_id>,,;/^6$/!d;/^6$/{g;:1;h;s,<item_id>\([0-9]*\)<\/item_id>,,;t2;:3;g;n;b1};d;b;:2;/^6$/!Q;b3' file

Usar um par de vars torna isso um pouco melhor, mas não tanto

reg='<item_id>\([0-9]*\)<\/item_id>'
item='6'

sed -e "h;s,$reg,,;/^$item$/!d;/^$item$/{g;:1;h;s,$reg,,;t2;:3;g;n;b1};d;b;:2;/^$item$/!Q;b3" file

E um POSIXfyed parece sem sentido:

sed -ne 'h;s,<item_id>\([0-9]*\)<\/item_id>,,;/^6$/!d;/^6$/{g;:1;h;s,<item_id>\([0-9]*\)<\/item_id>,,;t2;:3;g;p;n;b1;};d;b;:2;/^6$/!q;b3' file

Apenas este código estendido pode (?) ser mais legível:

reg='<item_id>\([0-9]*\)<\/item_id>'
item='6'

sed -ne 'h;                 # hold copy of line being processed.
         s,'"$reg"',,;    # extract included number.
         /^'"$item"'$/!d;   # Not the correct number?: get next line.
         /^'"$item"'$/{
         g;                 # restore line from hold buffer.
         :1
         h;                 # store successive lines in hold buffer.
         s,'"$reg"',,;    # extract the number (again).
         t2
         :3
         g;                 # restore the line back from hold buffer.
         p;                 # print the line.
         n;                 # go to process next line.
         b1
         };                 # end of loop.
         d;                 # avoid printing this last line.
         q;                 # quit the sed script.
         :2
         /^'"$item"'$/!q;   # Test if the number is the one selected.
         b3
        ' file

Talvez você deva usar outro idioma ou ferramenta.

    
por 10.11.2018 / 21:24
5

Supondo que este é um documento XML bem formado, o seguinte usa XMLStarlet para selecionar os info_id nós cujos valores são 6 e, em seguida, o irmão seguinte imediatamente info1 e info2 nós:

$ xmlstarlet sel -t -m '//item_id[. = 6]' \
    -c . -nl \
    -c './following-sibling::info1[1]' -nl \
    -c './following-sibling::info2[1]' -nl file.xml
<item_id>6</item_id>
<info1>abc</info1>
<info2>123</info2>
<item_id>6</item_id>
<info1>def</info1>
<info2>456</info2>
<item_id>6</item_id>
<info1>ghi</info1>
<info2>789</info2>

Como alternativa, ignore o que os seguintes nós são chamados:

xmlstarlet sel -t -m '//item_id[. = 6]' \
    -c . -nl \
    -c './following-sibling::*[1]' -nl \
    -c './following-sibling::*[2]' -nl file.xml
    
por 10.11.2018 / 22:03