Qual é a maneira mais simples de remover linhas de um arquivo que corresponde a linhas de outro arquivo?

5

Qual é a maneira mais simples de remover linhas de um arquivo que corresponde a linhas de outro arquivo? Por exemplo, se eu tiver os seguintes arquivos:

file1.csv:

[email protected]

file2.csv:

1,[email protected],somehash1
2,[email protected],somehash2
3,[email protected],somehash3

Como resultado, gostaria de ter file3.csv :

1,[email protected],somehash1
3,[email protected],somehash3

Qual é o caminho mais rápido para resolver essa tarefa? Esses arquivos têm alguns GB de tamanho.

    
por A B 26.07.2011 / 01:05

6 respostas

5

grep -v -F -f file1.csv file2.csv > file3.csv parece o mais simples. Mas você deve fazer testes de desempenho com arquivos menores primeiro. (Eu concordo com o comentário de soandos de que arquivos tão grandes podem precisar de uma solução dedicada.)

    
por 26.07.2011 / 14:51
3
awk -F, '
  FILENAME == ARGV[1] {to_remove[$1]=1; next}
  ! ($2 in to_remove) {print}
' file1.csv file2.csv > file3.csv

Você precisa ter memória suficiente para ler no arquivo1 de uma só vez.

Aqui está outra opção: join

$ join -t , -v 2 -1 1 -2 2 file1.csv file2.csv
[email protected],1,somehash1
[email protected],3,somehash3

No entanto, na página man "Importante: FILE1 e FILE2 devem ser classificados nos campos de junção." então, considere isso em sua decisão.

    
por 26.07.2011 / 02:44
1

Você poderia fazer um loop por cada linha no arquivo1 e fazer o grep das linhas correspondentes do arquivo2?

cp file2.csv file3.csv
cat file1.csv | while read line; do
    grep -v ${line%?} file3.csv > temp.csv
    cat temp.csv > file3.csv
done
rm -f temp.csv

Não testado.

Editar: Testado, parece funcionar OK. Apenas certifique-se de ter uma nova linha no arquivo1.

    
por 26.07.2011 / 01:28
1

O arquivo1.csv precisa permanecer inalterado?

sed 's|.*|/^&.*/d|' file1.csv > file1.sed
sed -f file1.sed file2.csv > file3.csv 

Eu não sei quanta memória ele consome. AFAIK, ele testará o arquivo inteiro -sed a cada vez em toda a entrada (2.csv).

Se a entrada estiver classificada e os padrões também forem classificados, você poderá implementar uma solução mais rápida.

    
por 26.07.2011 / 02:54
0

Certifique-se de que file3.csv exista (e esteja vazio)

echo > file3.csv
diff file1.csv file2.csv | patch file3.csv

Et voilá!

    
por 26.07.2011 / 02:56
0

Isso não precisa de uma "solução codificada". Se você classificar as linhas primeiro, a complexidade algorítmica será reduzida em várias ordens de magnitude.

Veja esta resposta para um melhor desempenho, tanto em termos de tempo de CPU como de memória:

link

    
por 21.06.2016 / 01:57