Deleção de texto entre padrões em múltiplas linhas em relação ao texto dentro do padrão

0

Eu tenho um bloco de texto que preciso excluir, no entanto, somente se ele contiver um texto específico dentro do bloco:

...
<script language="JavaScript">
    var somethingA = 0;
    var somethingB = 0;
    var somethingC = 0;
    // do some stuff
</script>

<script language="JavaScript">
    var somethingA = 0;
    var somethingC = 0;
    var somethingD = 0;
    // do some stuff
</script>
....

Eu quero remover apenas o bloco <script> que tem var somethingB . Pode haver qualquer quantidade de <script> de blocos no arquivo em qualquer posição.

Eu esperava usar o sed fazendo algo como:

sed 's/<script/,/<\/script>/ D'

No entanto, não consigo descobrir como excluir apenas o bloco com var somethingB .

PS: Eu também poderia usar perl ou awk. Eu preferiria usar sed por causa da consistência, mas se for mais fácil em perl e / ou awk eu mudaria de velocidade rapidamente nesse ponto. Obrigado!

    
por Matt 29.12.2014 / 21:57

3 respostas

1

Se uma solução parcial em vim for aceitável:

:%s/<script [^<]*\(\n[^<]*\)*somethingB.*\(\n[^<]*\)*<\/script>//g

mas não funcionará se houver outras tags dentro de <script> , porque usando [^<] , o padrão não pode conter < .

    
por 17.03.2016 / 16:06
0

Eu não tenho uma solução simples. Na verdade, ele usa o awk para codificar o algoritmo necessário na linguagem C-like do awk. Supondo que o texto a filtrar esteja em um arquivo chamado 'filename':

awk 'BEGIN { curr=0 } \
     /<script .*>/ { in_block=1; del_block=0 } \
     /<\/script>/ { in_block=0; blockend=1 } \
     /var[[:space:]]+somethingB/ { if (in_block==1) \
                                     { del_block=1 } } \
    { if (in_block==0) \
        { if (blockend==0) \
            # Neither in a block nor block end reached.
            # Just print the line
            { print } \
          else \
            { # End of a block reached. Do block end handling
              # just this one time. Block end flag off
              blockend=0
              if (del_block==1) \
                { # delete the block. Just throw away the lines
                  # in the lines array
                  curr=0 } \
              else \
                { # End of block and no delete. Print it out
                  for (i=0; i<curr; i++) \
                    { print line[i] }
                    print   # Print the </script> line
                      # use line-array for the next block
                      curr=0 \
                } \
            } \
        } \
      else \
        { # In a block. Save the current line for later
          line[curr]=$0
          curr++ } \
    }' filename

O padrão para </script> (o marcador final de um bloco) é um pouco simples. Espera que seja exatamente escrito assim sem espaços. Se ele puder conter espaços em branco, você pode escrever assim:

/<[[:space:]]*\/script[[:space:]]*>/ 

O padrão para var somethingB é var - um ou mais espaços em branco - somethingB , que é provavelmente o que você está procurando. Se você quiser que seja corrigido em exatamente um espaço entre var e somethingB , é mais simples: /var somethingB/

    
por 30.12.2014 / 15:07
0

Isso deve ser possível em sed diretamente. Como não sou nenhum assistente sed , preciso de duas execuções.

  1. Na primeira execução, preparamos o arquivo para garantir que os blocos <script>...</script> sejam substituídos por linhas em branco:

    sed -e '/<script/i\ ' -e '/script>/a\ ' code.js
    

    Não é ciência de foguetes: i insere uma linha antes da linha correspondente a um padrão, a em conformidade acrescenta uma linha após a linha correspondente a um padrão. Em ambos os casos, a linha consiste em apenas um espaço em branco.

    É necessário que sed detecte cada bloco separadamente, ou seja, não avidamente na segunda etapa.

  2. A segunda execução mata os blocos com var somethingB :

    sed '/<script/,/script>/{H;d;};x;/var somethingB/d'
    
    • /<script/,/script>/{H;d;} move um bloco para o espaço de espera do sed ( H acrescenta espaço, d exclui do espaço padrão)
    • x troca o espaço de armazenamento com o espaço padrão
    • se o padrão /var somethingB/ fizer a exclusão ( d ) do espaço de padrão, que contém o bloco <script> completo.
    • finalmente, sed imprime implicitamente o espaço do padrão.

      Minha referência aqui foi o Tutorial do Unix Sed .

  3. Então, em uma linha de comando com um bom canal:

    sed -e '/<script/i\ ' -e '/script>/a\ ' code.js | sed '/<script/,/script>/{H;d;};x;/var somethingB/d'
    

    Se você quiser, use uma terceira sed instance para se livrar das linhas vazias adicionais:

    sed '/^ $/d'
    
por 05.01.2015 / 18:20