Comparando dois arquivos de texto

5

Eu tenho 2 arquivos csv grandes, file1.csv que se parecem com isso

1,2,3,4
1,4,5,6
1,7,8,9
1,11,13,17

arquivo2.csv que se parece com isso

1,2,3,4
1,7,8,9
2,4,9,10
13,14,17,18

Estes são apenas números aleatórios que eu inventei, basicamente os dois números idênticos e ordenados. Eu quero comparar file1.csv e file2.csv e, em seguida, copie as linhas que estão presentes no file1.csv mas não no arquivo2.csv para file3.csv. o delimitador é vírgula obviamente

Eu tentei

comm -2 -3 file.csv file2.csv > file3.csv

e eu tentei

diff -u file.csv file2.csv >> file3.csv

Ambos não funcionaram porque o arquivo3 era maior que o arquivo1 e o arquivo2. Eu tentei diferentes comandos diff e comm , às vezes é maior que arquivo2 e aproximadamente o mesmo tamanho que arquivo file1, eu sei que arquivo3 tem que ser significativamente menor em tamanho que arquivo1 e arquivo2. E é claro que eu olhei para file3, não os resultados que eu queria

Nesse ponto, sei que isso pode ser feito com diff ou comm , mas não sei o comando a ser usado.

    
por Lynob 07.11.2014 / 13:29

4 respostas

5

Experimente este comando:

 grep -v -f file2.csv file1.csv > file3.csv

De acordo com o manual do grep :

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

Como Steeldriver disse em seu comentário é melhor adicionar também -x e -F que:

  -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.)
  -x, --line-regexp
          Select  only  those  matches  that exactly match the whole line.
          (-x is specified by POSIX.)

Então, melhor comando é:

 grep -xvFf file2.csv file1.csv > file3.csv

Esse comando usa file2.csv linha como padrão e linha de impressão de file1.csv que não corresponde ( -v ).

    
por Lety 07.11.2014 / 13:44
7

Para poder usar comm , você precisa classificar as linhas primeiro.

comm -23 <(sort file1.csv) <(sort file2.csv) > file3.csv
    
por choroba 07.11.2014 / 13:49
3

Uma opção de python:

#!/usr/bin/env python3

import sys

def readfile(file):
    with open(file) as src:
        return [line.strip() for line in src.readlines()]

lines_1 = readfile(sys.argv[1]); lines_2 = readfile(sys.argv[2])

for line in lines_1:
    if not line in lines_2:
        print(line)

Saída:

1,4,5,6
1,11,13,17

Cole o script em um arquivo vazio como extract.py , torne-o executável e execute-o pelo comando:

<script> <file_1> <file_2>

Ou, para escrevê-lo diretamente no arquivo_3:

<script> <file_1> <file_2> >file_3
    
por Jacob Vlijm 07.11.2014 / 13:48
3

Usando o comando diff do grep e não é necessário armazenar.

Saída se existirem linhas no arquivo1, mas não no arquivo2:

$ diff file{1,2}.csv | grep -Po "^< \K.*"
1,4,5,6
1,11,13,17

E saída se houver linhas no arquivo2, mas não no arquivo1, com apenas a alteração do ângulo esquerdo ( < ) para o ângulo direito ( > ):

$ diff file{1,2}.csv | grep -Po "^> \K.*"
2,4,9,10
13,14,17,18
    
por αғsнιη 07.11.2014 / 14:46