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 <
.
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!
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 <
.
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/
Isso deve ser possível em sed
diretamente. Como não sou nenhum assistente sed
, preciso de duas execuções.
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.
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 /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 .
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'