2012-05-07 11 views
8

Ho due file A e B. Voglio trovare tutte le linee in A che non sono in B. Qual è il modo più veloce per farlo in bash/usando le utility standard di Linux? Ecco cosa ho provato finora:Come trovare la differenza di set di due file?

for line in `cat file1` 
do 
    if [ `grep -c "^$line$" file2` -eq 0]; then 
    echo $line 
    fi 
done 

Funziona, ma è lento. C'è un modo più veloce per farlo?

+0

Puoi mostrare qualche codice o spiegare cosa hai provato? La tua domanda così com'è sembra che tu voglia che noi facciamo tutto il lavoro per te. Spesso, mostrare il codice aiuterà a incoraggiare più risposte e risultati migliori. – jmort253

+0

Dovresti anche definire cosa ti aspetti da "più veloce". Riguarda il tempo di elaborazione o il tempo impiegato a scrivere il codice. Per il secondo, vorrei andare per qualcosa come 'diff A B | grep '^ -' ' – tonio

+0

@ jmort253, grazie, ho modificato la domanda per aggiungere ulteriori dettagli – spinlok

risposta

20

The BashFAQdescribes doing exactly this with comm, che è il metodo canonicamente corretta.

# Subtraction of file1 from file2 
# (i.e., only the lines unique to file2) 
comm -13 <(sort file1) <(sort file2) 

diff è meno appropriato per questa attività, poiché tenta di operare su blocchi anziché su singole righe; in quanto tale, gli algoritmi che deve utilizzare sono più complessi e meno efficienti in termini di memoria.

comm è stato part of the Single Unix Specification da SUS2 (1997).

+0

Questo è esattamente quello che stavo cercando! Grazie! – spinlok

+0

Questo è un programma a portata di mano. Non l'ho visto prima. Mi chiedo quali altre piccole gemme di applicazioni shell abbiano mancato la mia vita passata come amministratore delegato. –

1

Il programma "diff" è un programma standard unix che esamina le differenze tra i file.

% cat A 
a 
b 
c 
d 
% cat B 
a 
b 
e 
% diff A B 
3,4c3 
< c 
< d 
--- 
> e 

Con un semplice grep e tagliare si possono selezionare le linee in A, non in B. Si noti che il taglio è piuttosto semplicistica e spazi nelle linee getterebbe via ... ma il concetto è lì.

% diff A B | grep '^<' | cut -f2 -d" " 
c 
d 
2

Se si desidera semplicemente le linee che sono file di A, ma non in B, è possibile ordinare i file, e confrontarli con diff.

sort A > A.sorted 
sort B > B.sorted 
diff -u A.sorted B.sorted | grep '^-' 
+4

Non hai bisogno di file temporanei per quello. 'diff <(ordina A) <(ordina B) | grep '^ -' ' – jordanm

+0

Sì, è ancora più chiaro in questo modo, grazie – tonio

Problemi correlati