Existe uma ferramenta para obter as linhas em um arquivo que não estão em outro?

104

Existe alguma ferramenta que possa obter linhas que o arquivo A contém, mas o arquivo B não contém? Eu poderia fazer um pequeno script simples com, por exemplo, perl, mas se algo parecido já existir, eu salvarei meu tempo a partir de agora.

    
por daisy 02.01.2012 / 14:18

6 respostas

144

Sim. A ferramenta padrão grep para procurar arquivos por strings de texto pode ser usada para subtrair todas as linhas em um arquivo de outro.

grep -F -x -v -f fileB fileA

Isso funciona usando cada linha no arquivo B como um padrão ( -f fileB ) e tratando-a como uma string simples para corresponder (não uma regex regular) ( -F ). Você força a correspondência a acontecer na linha inteira ( -x ) e imprime somente as linhas que não correspondem ( -v ). Portanto, você está imprimindo as linhas no arquivo A que não contêm os mesmos dados de qualquer linha no arquivo B.

A desvantagem dessa solução é que ela não considera a ordem da linha e, se sua entrada tiver linhas duplicadas em lugares diferentes, talvez você não consiga o que espera. A solução para isso é usar uma ferramenta de comparação real, como diff . Você poderia fazer isso criando um arquivo diff com o valor de contexto em 100% das linhas no arquivo e, em seguida, analisando-o apenas para as linhas que seriam removidas se convertesse o arquivo A no arquivo B. (Observe também este comando) remove a formatação do diff depois de obter as linhas certas.)

diff -U $(wc -l < fileA) fileA fileB | sed -n 's/^-//p' > fileC
    
por 02.01.2012 / 14:57
55

A resposta depende muito do tipo e formato dos arquivos que você está comparando.

Se os arquivos que você está comparando são arquivos de texto ordenados, então a ferramenta GNU escrita por Richard Stallman e Davide McKenzie chamou comm pode realizar a filtragem que você está procurando. Faz parte dos coreutils.

Exemplo

Digamos que você tenha os 2 arquivos a seguir:

$ cat a
1
2
3
4
5

$ cat b
1
2
3
4
5
6

Linhas no arquivo b que não estão no arquivo a :

$ comm <(sort a) <(sort b) -3
    6
    
por 03.01.2012 / 07:30
32

de stackoverflow ...

comm -23 file1 file2

-23 suprime as linhas que estão em ambos os arquivos, ou apenas no arquivo 2. Os arquivos devem ser classificados (eles estão no seu exemplo), mas se não, encaminhá-los através de ordenação primeiro ...

Veja a página de manual aqui

    
por 07.06.2013 / 21:51
7

Os métodos grep e comm (com classificação) levam um tempo longo em arquivos grandes. SiegeX e ghostdog74 compartilharam dois grandes métodos awk para extrair linhas exclusivas para um dos dois arquivos no Stack Overflow:

$ awk 'FNR==NR{a[$0]++}FNR!=NR && !a[$0]{print}' file1 file2

$ awk 'FNR==NR{a[$0]++;next}(!($0 in a))' file1 file2
    
por 29.09.2013 / 07:36
4

Se os arquivos forem grandes e você não tiver uma ordem personalizada para suas entradas, o grep demorará muito. Uma alternativa rápida seria

sort file1 > 1 
sort file2 > 2 
diff 1 2 | grep "\>" | sed -e 's/> //'

[file2-file1 resulta em screen, pipe to file, etc.]

A alteração de > para < obteria a subtração oposta. rm 1 2

    
por 24.08.2012 / 17:12
2

Você também pode considerar o vimdiff, ele destaca as diferenças entre os arquivos em um editor vim

    
por 21.02.2012 / 11:26