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.