Isso é bastante simples - basta uma pequena coordenação entre os dois buffers de sed . Por exemplo:
sed -n 'H;/fish/!d;$!n;x;p;G
' <<\INFILE
this is a cow
this is a goat
this is a some fish
this is a fishie
this is a fish
this is a lion
this is a cat
INFILE
Esse comando anexa todas as linhas a H old space após um caractere \n ewline inserido. Qualquer linha que não ! não corresponde a /fish/ é imediatamente a partir de então d da saída. O que nos deixa com apenas /fish/ linhas. Portanto, a linha é sobrescrita com a linha de entrada n ext. Então padrão e h espaços antigos são trocados - nós fizemos apenas H old a linha depois de tudo. Agora o espaço de padrão é H old space e vice-versa. Então, apenas p rint foi salvo da última vez que uma linha /fish/ foi correspondida.
Isso só pode levar até a última ocorrência de uma correspondência, porque é apenas p rints quando encontra uma correspondência - e armazena as linhas intermediárias nesse intervalo. Ainda assim, ele armazena apenas o mínimo necessário entre as correspondências - cada vez que os buffers são e x alterados, eles são atualizados. Aqui está sua saída:
this is a cow
this is a goat
this is a some fish
this is a fishie
this is a fish
Muito obrigado a don cristi por me mostrar que às vezes eu pulei um peixe. Agora, ele certifica-se de empurrar o buffer para ambas as extremidades cada vez que ele é atualizado - e cada vez para sobrescrever o espaço padrão atual antes de excluí-lo - no caso. Ele funcionará com um peixe na primeira linha ou no último, e qualquer linha no meio, tanto quanto eu puder dizer.
Outra coisa que eu estava fazendo era puxar a linha n ext na última linha - que é um grande sed no-no. Obrigado novamente por me ajudar com isso também.
Um exemplo mais completo:
sed 'x;/./G;//!x;/fish/p;//s/.*//;x;d'
Isso lida com alguns problemas em torno do outro melhor, espero. Os espaços padrão / h old são e x alterados a cada ciclo - e isso é para evitar obter linhas em branco extras como resultado da edição s/// ubstitution no final do comando. Portanto, os buffers são trocados e, se o buffer de manutenção não estiver vazio, a linha atual é anexada nesse buffer após um caractere \n ewline - que é onde as linhas extras viriam de outra forma. Senão os buffers são apenas trocados de volta e o h old space permanece vazio para o ciclo atual. Por mais que eu saiba, este comando preserva todas as linhas em branco e tudo mais - mas simplesmente pára a impressão na última partida.
Algumas das dificuldades que tive com isso são comumente associadas com h old space - a única maneira de usá-lo efetivamente é ficar aquém do ciclo de linha para comparar as linhas antigas com as mais antigas. Minha preferência usual é por um loop N;P;D . Você pode fazer isso usando algo como essas ...
sed -ne :n -e '/fish/!N;//p;//!bn'
Há sed anexa continuamente a linha de entrada N ext ao espaço padrão e b ranchos de volta ao rótulo :n para tentar novamente se peixe não corresponder a nenhum dos linhas que construiu até agora. Apenas p rints linhas - ou sequências de linha - que correspondem a fish antes de descarregar o conteúdo no final do ciclo de linha e começar de novo com um novo buffer.
Eu propositadamente não testei a última linha aqui - se a última linha coincidir será impressa, senão - e com -n isto é válido mesmo para o GNU sed - o laço apenas terminará com o arquivo todo sua própria última linha ou não.