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