
Diga, tenho dois comandos que retornam algum texto. Por exemplo:
$ ./c1
/usr/bin/foo
/usr/bin/bar
/usr/bin/baz
$ ./c2
/usr/bin/foo
/usr/bin/qux
/usr/bin/buzz
/usr/bin/bar
Quero remover as linhas duplicadas; ou seja, a saída será (a ordem não é importante):
/usr/bin/baz
/usr/bin/qux
/usr/bin/buzz
Como eu faria isso?
Responder1
Um pipeline bastante simples deve resolver o problema:
(./c1; ./c2) | sort -u
Os parênteses vão para stdout de ambos ./c1
e ./c2
para stdin do sort
comando. A opção -u
imprime apenas 1 de cada grupo de linhas correspondentes.
Obrigado a John WH Smith por notar uma simplificação e a Bakuriu pela visão.
Responder2
Com comm
de GNU coreutils
:
$ comm -3 <(sort -u <(./c1)) <(sort -u <(./c2)) | tr -d '\t'
/usr/bin/baz
/usr/bin/buzz
/usr/bin/qux
De man comm
:
Compare sorted files FILE1 and FILE2 line by line.
With no options, produce three-column output. Column one contains
lines unique to FILE1, column two contains lines unique to FILE2, and
column three contains lines common to both files.
-1 suppress column 1 (lines unique to FILE1)
-2 suppress column 2 (lines unique to FILE2)
-3 suppress column 3 (lines that appear in both files)
Responder3
awk-pipe para deixar passar apenas a primeira ocorrência de uma linha de entrada:
( ./c1 ; ./c2 ) | awk '!u[$0]++'
Isso não leva tempo para classificar, mas precisa de uma memória das linhas vistas. Portanto, para grandes quantidades de informações sort
e uniq
pode ser melhor ...
Responder4
Eu recomendaria utilizar sed
para analisar o texto e remover linhas duplicadas. Então o primeiro comando mantém a linha duplicada
sed '$!N; /^\(.*\)\n\1$/!P; D'
O segundo comando irá deletar as duplicatas
sed -n 'G; s/\n/&&/; /^\([ -~]*\n\).*\n\1/d; s/\n//; h; P'