Diferença de dois arquivos grandes

Diferença de dois arquivos grandes

Eu tenho "test1.csv" e contém

200,400,600,800
100,300,500,700
50,25,125,310

e test2.csv e contém

100,4,2,1,7
200,400,600,800
21,22,23,24,25
50,25,125,310
50,25,700,5

agora

diff test2.csv test1.csv > result.csv

é diferente de

diff test1.csv test2.csv > result.csv

Não sei qual é a ordem correta, mas quero outra coisa, ambos os comandos acima produzirão algo como

2 > 100,4,2,1,7
   3 2,3c3,5
   4 < 100,300,500,700
   5 < 50,25,125,310
   6 \ No newline at end of file
   7 ---
   8 > 21,22,23,24,25
   9 > 50,25,125,310

Quero gerar apenas a diferença, portanto results.csv deve ficar assim

100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5

Eu tentei diff -qe diff -smas eles não funcionaram. A ordem não importa, o que importa é que quero ver apenas a diferença, sem > nem < nem espaço em branco.

grep -FvFfuncionou em arquivos menores, não em arquivos grandes

o primeiro arquivo contém mais de 5 milhões de linhas, o segundo arquivo contém 1300.

então results.csv deve resultar em aproximadamente 4.998.700 linhas

Eu também tentei grep -F -x -v -f o que não funcionou.

Responder1

Parece um trabalho para comm:

$ comm -3 <(sort test1.csv) <(sort test2.csv)
100,300,500,700
    100,4,2,1,7
    21,22,23,24,25
    50,25,700,5

Conforme explicado em man comm:

   -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)

Isso -3significa que apenas as linhas exclusivas de um dos arquivos serão impressas. No entanto, eles são recuados de acordo com o arquivo em que foram encontrados. Para remover a guia, use:

$ comm -3 <(sort test1.csv) <(sort test2.csv) | tr -d '\t'
100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5

Nesse caso, você nem precisa classificar os arquivos e pode simplificar o procedimento acima para:

comm -3 test1.csv test2.csv | tr -d '\t' > difference.csv

Responder2

Usando grepcom bashsubstituição de processo:

$ cat <(grep -vFf test2.csv test1.csv) <(grep -vFf test1.csv test2.csv)
100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5

Para salvar a saída como results.csv:

cat <(grep -vFf test2.csv test1.csv) <(grep -vFf test1.csv test2.csv) >results.csv
  • <()é obashpadrão de substituição de processo

  • grep -vFf test2.csv test1.csvencontrará as linhas exclusivas apenas paratest1.csv

  • grep -vFf test1.csv test2.csvencontrará as linhas exclusivas apenas paratest2.csv

  • Finalmente estamos resumindo os resultados porcat

Ou comoOli sugeriu, você também pode usar o agrupamento de comandos:

$ { grep -vFf test2.csv test1.csv; grep -vFf test1.csv test2.csv; }
100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5

Ou apenas execute um após o outro, pois ambos estão escrevendo para STDOUT e serão adicionados:

$ grep -vFf test2.csv test1.csv; grep -vFf test1.csv test2.csv
100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5

Responder3

Se a ordem das linhas não for relevante, use awkou perl:

awk '{seen[$0]++} END {for (i in seen) {if (seen[i] == 1) {print i}}}' 1.csv 2.csv

Use greppara obter as linhas comuns e filtrá-las:

grep -hxvFf <(grep -Fxf 1.csv 2.csv) 1.csv 2.csv

O grep interno obtém as linhas comuns, então o grep externo encontra linhas que não correspondem a essas linhas comuns.

Responder4

Como o pedido não precisa ser preservado, basta:

sort test1.csv test2.csv | uniq -u
  • sort test1.csv test2.csv: mescla e classifica test1.csvetest2.csv
  • uniq -u: imprime apenas as linhas que não possuem duplicatas

informação relacionada