Ferramenta no unix para subtrair arquivos de texto?

16

Eu tenho um arquivo grande composto por campos de texto separados por ponto e vírgula na forma de uma tabela grande. Foi ordenado. Eu tenho um arquivo menor composto pelos mesmos campos de texto. Em algum momento, alguém concatenou esse arquivo com outras pessoas e, em seguida, fez uma classificação para formar o arquivo grande descrito acima. Eu gostaria de subtrair as linhas do arquivo pequeno do arquivo grande (por exemplo, para cada linha do arquivo pequeno, se existir uma sequência correspondente no arquivo grande, exclua essa linha no arquivo grande).

O arquivo é mais ou menos assim

GenericClass1; 1; 2; NA; 3; 4;
GenericClass1; 5; 6; NA; 7; 8;
GenericClass2; 1; 5; NA; 3; 8;
GenericClass2; 2; 6; NA; 4; 1;

etc

Existe uma maneira rápida e elegante de fazer isso ou eu tenho que usar o awk?

Escher
fonte

Respostas:

28

Você pode usar grep. Dê a ele o arquivo pequeno como entrada e peça para encontrar linhas não correspondentes:

grep -vxFf file.txt bigfile.txt > newbigfile.txt

As opções usadas são:

   -F, --fixed-strings
          Interpret PATTERN as a  list  of  fixed  strings,  separated  by
          newlines,  any  of  which is to be matched.  (-F is specified by
          POSIX.)
   -f FILE, --file=FILE
          Obtain  patterns  from  FILE,  one  per  line.   The  empty file
          contains zero patterns, and therefore matches nothing.   (-f  is
          specified by POSIX.)

   -v, --invert-match
          Invert the sense of matching, to select non-matching lines.  (-v
          is specified by POSIX.)
   -x, --line-regexp
          Select only those matches that exactly match the whole line.  
          (-x is specified by POSIX.)
terdon
fonte
Bom, funcionou perfeitamente. Muito obrigado.
Escher
11
É legal que funcionou, mas parece-me que teria sido melhor com a -xopção também, caso uma linha no arquivo menor me acontecesse uma substring de outra linha no arquivo principal. Além disso, é bem possível que a resposta de @ UlrichSchwarz seja mais rápida.
rici 30/09
18

comm é seu amigo:

NAME comm - compara dois arquivos classificados linha por linha

SYNOPSIS comm [OPÇÃO] ... ARQUIVO1 ARQUIVO2

DESCRIÇÃO Compare os arquivos classificados FILE1 e FILE2 linha por linha.

   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)

( commprovavelmente terá um benefício de desempenho, greppois leva em consideração a classificação.)

Por exemplo:

comm -1 -3 file.txt bigfile.txt > newbigfile.txt
Ulrich Schwarz
fonte
2
Bom ponto sobre o uso de comm over grep para listas classificadas. Essa seria uma resposta melhor se você desse um exemplo específico de linha de comando, como #comm -1 -3 file.txt bigfile.txt > newbigfile.txt
Steve Midgley
Confirmo que tentei o comando grep relatado acima com arquivos em torno de 100 MB e recebi um erro "morto". Tentando com comm terminou com sucesso.
Gianluca Casati
Redirecionamento de comando é útil para arquivos não ordenados ou se precisar de mais de dois arquivos:comm -1 -3 <(sort BAD.txt GOOD.txt) <(sort FILES.txt)
odinho - Velmont