Para um conjunto de números de linha ... Extrai o conteúdo entre a primeira e a última ocorrência de diferentes padrões

1

Eu tenho um conteúdo semelhante em um arquivo. Eu tenho uma lista de números de linha comigo dizer 1,2, 4.

  1. Pode alimentar todos os #s da linha necessários
  2. Extraia o conteúdo entre a primeira ocorrência e a última ocorrência de </book>

Dados:

</p><p>abc</p></book><book><p style="text-indent:0em;">def</p></book><book><p>ghi</p><p style="text-indent:0em;"></book><book><div><p>  
</div><p>123</p></book><book><p style="text-indent:0em;">456</p><p>789</p><p style="text-indent:0em;"></book><book><div><p>  
<div><p>nothing !!!</p></div>  
</p><p>ABC</p></book><book><p style="text-indent:0em;">DEF</p></book><book><p>GHI</p><p style="text-indent:0em;"></book><book><div><p>JKL</p></div></book><div>  

Nºs da linha de entrada: 1, 2, 4 (que eu quero alimentar no comando)

Saída desejada:

<book><p style="text-indent:0em;">def</p></book><book><p>ghi</p><p style="text-indent:0em;"></book>
<book><p style="text-indent:0em;">456</p><p>789</p><p style="text-indent:0em;"></book>
<book><p style="text-indent:0em;">DEF</p></book><book><p>GHI</p><p style="text-indent:0em;"></book><book><div><p>JKL</p></div></book>
    
por Samuel Finny 19.09.2017 / 08:35

2 respostas

3

1) Extraia linhas específicas

Em seu exemplo de quatro linhas para extrair a 1ª, a 2ª e a 4ª linha, será fácil excluindo a terceira linha:

sed 3d file

Mas seu arquivo é provavelmente mais complicado, então uma solução mais geral seria fazer

sed -e 1b -e 2b -e 4b -e d file

Portanto, para cada linha que deve ser mantida, você pula para o final do script com b e exclui todos os arquivos restantes.

Para uma lista mais longa de números de linha, convém gerar o script:

sed $(for i in 1 2 4; do echo "-e ${i}b"; done) -e d file

Mas parece que não se trata dos números de linha, mas se há <book> s nessa linha. Se isso for verdade, é melhor esquecer os números de linha e fazer

sed '/<book>/!d' 

2) extraindo o conteúdo

Greedy * da regexp não é amigo de tarefas como esta. É por isso que minha versão pessoal de sed tem uma opção o para o comando s para substituir o nly pela parte correspondente:

sed '/<book>/!d;s_<book>.*</book>_&_o' 

Mas isso não vai funcionar para você, então você precisa de mais malabarismos com o regex:

sed '/<book>/!d;s_<book>_\n&_;s_.*\n__;s_\(.*</book>\).*__' file

Se a sua versão de sed não suportar \n na sequência de substituição, use uma nova linha real (com uma barra invertida):

sed '/<book>/!d;s_<book>_\
&_;s_.*\n__;s_\(.*</book>\).*__' file
    
por 19.09.2017 / 10:04
1

com perl :

#!/usr/bin/env perl

use strict;
use warnings;

use v5.10;

my @lines = (1, 2, 4);

while(<>) {
    next unless $. ~~ @lines;
    chomp;
    s#.*?(<book>.*</book>).*#$1#;
    say
}
    
por 19.09.2017 / 10:48