sed -e 's/\(match\)\([_[:alnum:]]*\)\(\(.*\)\n\)*/\
/2;tc' -e b -e :c -e 's///'
A sequência acima sempre tratará apenas a primeira e a segunda ocorrência de match
em uma linha - independentemente de quantos possam existir em uma linha.
Funciona fazendo a primeira s///
ubstitution na ocorrência de s///2
cd do padrão e, em seguida, se a substituição t
ests for bem-sucedida, b
ranching para o rótulo :c
ontinue ou se não, b
ranching fora do script.
Portanto, quando houver uma segunda correspondência do padrão, o padrão será repetido para o comando 2cd s///
ubstitution. Mas quando não há as linhas são impressas como de costume.
O importante é a subexpressão \(\(.*\)\n\)*
. A subexpressão corresponde apenas a uma cadeia nula para o primeiro comando s///2
, porque um \n
ewline só pode ocorrer em um espaço de padrão sed
como resultado de uma edição. Mas quando o padrão for repetido, o \(\(.*\)\n\)*
corresponderá a qualquer / todos os caracteres que ocorram entre os dois match
es porque o s///
ubstitution anterior inseriu um \n
ewline ao substituir [_[:alnum:]]*
. E assim, o mesmo padrão repetido pode significar duas coisas diferentes, dependendo de seu contexto no script.
Embora a versão acima deva funcionar como escrita para qualquer POSIX sed
(ênfase em deve - muitos sed
s não obedecem a repetidos padrões de subexpressão) , com GNU sed
você pode escrevê-lo um pouco mais curto:
sed -E 's/(match)(\w*)((.*)\n)*/\n/2;T;s///
' <<\IN
text match_something_here and !m!atch_xxx blablabla
text match_something_here and match_xxx blablabla
text match_something_else_here and match_xxx blablabla
text match_something_here and match_xxx blablabla match_xxx blablabla
text match_something_else_here and match_xxx blablabla match_xxx blablabla match_xxx blablabla
IN
... O bit <<\IN
a IN
é apenas uma entrada do documento aqui para que eu possa demonstrar como funciona - você provavelmente deve usar <input_file
em seu lugar. Observe também que mudei seu $something
e $xxx
para _something
e _xxx
porque entendo que esses sinais de dólar não devem ser incluídos no padrão de substituição, mas serão substituídos por outra coisa. Se for verdade, então você pode manter o \w*
ord escapar lá, ou, se você quiser literalmente cifrões incluídos, então você ainda deve definir sua própria classe de caracteres e adicioná-la como: [$_[:alnum:]]*
.
Observe que o tc' -e b -e :c -e
é encurtado para - com o GNU sed
- apenas um T
. Enquanto portably o t
est resultou em uma substituição bem-sucedida de b
ranching no ponto em que as linhas malsucedidas b
foram removidas, com GNU sed
você pode T
est para resultados sem sucesso - que ramifica-os diretamente e apenas as linhas restantes que ainda estão executando o script nesse ponto são aquelas que fizeram substituir com sucesso o segundo par de jogos por um \n
ewline.
Em qualquer caso, (dependendo do sed
) qualquer um dos itens acima será impresso:
text match_something_here and !m!atch_xxx blablabla
text match_something_here and match_something_here blablabla
text match_something_else_here and match_something_else_here blablabla
text match_something_here and match_something_here blablabla match_xxx blablabla
text match_something_else_here and match_something_else_here blablabla match_xxx blablabla match_xxx blablabla