Que tal este sed
one-liner:
sed -n '${;p;q;};N;/^ *\([^ ][^ ]* *[^ ][^ ]*\)\( .*\)*\n */{;s/\n.*//;h;G;D;};P;D' inputfile
Este foi um bom desafio complicado; obrigado! :)
Em um nível alto, o que isso faz é percorrer o arquivo de entrada comparando duas linhas de cada vez. Se as linhas coincidirem com as duas primeiras palavras, a linha segunda das duas será descartada e a linha próxima do arquivo será usada para comparar com a primeira linha. Se as linhas não coincidirem, a primeira será impressa e a segunda retida para comparação com as linhas posteriores. Quando o final do arquivo é atingido, a linha atualmente "mantida para comparação" é impressa.
Explicação de golpe a golpe:
-n doN't print lines by default; only if specified to print them.
${;p;q;}; if on the la$t line then Print the line and Quit.
N; append a newline followed by the Next line of the file to the pattern space
/^ *\([^ ][^ ]* *[^ ][^ ]*\)\( .*\)*\n */ A very tricky regex:
match any leading spaces, followed by a nonspace sequence, space or
multiple spaces, nonspace sequence, then optionally a space followed
by anything, then a newline, then any leading spaces, then the matched
two words from earlier again.
{; if that regex matched the pattern space, excecute the following.
s/\n.*//; delete the first newline and everything after it
h; copy the pattern space contents to the Hold space
G; append (Get) a newline followed by the hold space contents to the pattern space
D; delete everything in the pattern space up to the first newline, then start from the beginning of this sequence (with the ${ block)
}; end of block. Skip to here if the tricky regex didn't match.
P; Print everything in the pattern space up to the first newline.
D Delete the pattern space up to the first newline.
Observe que o acima é muito portátil. Deliberadamente. Só por um desafio eu queria que ele fosse executado sem ?
ou +
estar disponível (já que eles não são compatíveis com POSIX), o que torna a regex muito mais complicada.
Além disso, o fluxo lógico não inclui nenhuma ramificação, embora as ramificações sejam compatíveis com POSIX e estejam disponíveis universalmente. Por que eu fiz isso? É porque nem todas as implementações de sed
permitem que rótulos sejam especificados em um único liner. Eles exigem um \
e uma nova linha após o rótulo. O GNU sed permite rótulos em um one-liner e, por exemplo, o BSD sed não.
Os dois liners a seguir são exatamente iguais usando o GNU sed, a única diferença é que eles são mais robustos ao lidar com guias e espaços:
sed -n ':k;${;p;q;};N;/^\s*\(\S\+\s\+\S\+\)\(\s.*\)\?\n\s*/{;s/\n.*//;bk;};P;D' inputfile
sed -n ':k;${;p;q;};N;s/^\(\s*\(\S\+\s\+\S\+\)\(\s.*\)\?\)\n\s*.*$//;tk;P;D' inputfile
Eu principalmente fiz isso por diversão. :) Eu acho que a resposta do 1_CR é a melhor, e é claro que é muito mais simples.
Se seus requisitos ficarem um pouco mais complicados do que são atualmente e a abordagem dele não funcionar, a melhor ferramenta provavelmente será awk
. Mas ainda não aprendi awk
e aprendi sed
. :)