Removendo linhas comuns às saídas produzidas por dois comandos

5

Diga, eu 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

Eu 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?

    
por user2064000 26.06.2014 / 17:06

4 respostas

6

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)
    
por 26.06.2014 / 19:00
7

Um pipeline bastante simples deve fazer o truque:

(./c1; ./c2) | sort -u

Os parênteses obtêm stdout de ./c1 e ./c2 no stdin do comando sort . A opção -u imprime apenas 1 de cada grupo de linhas correspondentes.

Obrigado a John WH Smith por notar uma simplificação, e Bakuriu por um insight.

    
por 26.06.2014 / 17:15
4

awk-pipe para deixar somente a primeira ocorrência de uma linha de entrada passar por:

( ./c1 ; ./c2 ) | awk '!u[$0]++'

Isso não leva tempo para classificação, mas precisa de uma memória de linhas vistas. Então, para grandes quantidades de entrada, sort e uniq podem ser melhores ...

    
por 26.06.2014 / 17:31
0

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$/!P; D'

O segundo comando excluirá os duplicados sed -n 'G; s/\n/&&/; /^\([ -~]*\n\).*\n/d; s/\n//; h; P'

    
por 26.06.2014 / 17:14