2013-01-23 13 views
61

Ho due file (diciamo a.txt e b.txt), entrambi con un elenco di nomi. Ho già eseguito sort su entrambi i file.Trova linee da un file che non sono presenti in un altro file

Ora voglio trovare le linee da a.txt che non sono presenti in b.txt.

(ho trascorso molto tempo per trovare la risposta per questa domanda, in modo da documentare per riferimenti futuri)

risposta

101

Il comando si deve utilizzare non è diff ma comm

comm -23 a.txt b.txt 

Per impostazione predefinita, comm uscite 3 colonne: solo sinistra, solo destra, entrambi. Gli switch -1, -2 e -3 sopprimono queste colonne.

Quindi, -23 nasconde le giusti soli e entrambi colonne, mostrando le linee che appaiono solo nel primo file (a sinistra).

Se si desidera trovare le linee che appaiono in entrambi, è possibile utilizzare -12, che nasconde le sinistra-solo e destro soli colonne, lasciando con solo la colonna entrambi.

+9

Aggiungerò che funziona solo se entrambi i file sono ordinati. (So ​​che l'OP accennato ha ordinato i file, ma molte persone, me incluso, leggono il titolo della domanda e poi passano alle risposte) – user247866

+1

@ user247866: Fortunatamente comm è abbastanza gentile da dirti se non sono ordinati :) – marlar

20

La risposta semplice non ha funzionato per me perché non mi ero reso conto che comm corrisponda alla linea per riga, quindi le righe duplicate in un file verranno stampate come non esistenti nell'altro. Per esempio, se file1 conteneva:

Alex 
Bill 
Fred 

E file2 contenuta:

Alex 
Bill 
Bill 
Bill 
Fred 

Poi comm -13 file1 file2 sarebbe uscita:

Bill 
Bill 

Nel mio caso, ho voluto sapere solo che ogni stringa file2 esisteva in file1, indipendentemente dal numero di volte in cui quella riga si verificava in ogni file.

Soluzione 1: utilizzare il -u (unica) bandiera per sort:

comm -13 <(sort -u file1) <(sort -u file2)

Soluzione 2: (la prima risposta "di lavoro" che ho trovato) da unix.stackexchange:

fgrep -v -f file1 file2

Si noti che se file2 contiene dupli linee di cate che non esistono affatto nel file 1, fgrep genererà ciascuna delle linee duplicate.Si noti inoltre che i miei test totalmente non scientifici su un singolo laptop per un singolo dataset (abbastanza grande) hanno mostrato che la Soluzione 1 (utilizzando comm) è quasi 5 volte più veloce della Soluzione 2 (utilizzando fgrep).

+0

I i miei file sono stati ordinati e passati attraverso uniq. Comunque grazie per le altre soluzioni. – Sudar

2

Non sono sicuro del motivo per cui è stato detto che diff non deve essere utilizzato. Lo userei per confrontare i due file e quindi produrre solo le righe che sono nel file di sinistra ma non in quella di destra. Tali linee sono contrassegnati da diff con < quindi è sufficiente grep quel simbolo all'inizio della riga

diff a.txt b.txt | grep \^\< 
+1

È possibile utilizzare 'diff --new-line-format = --unchanged-line-format = a.txt b.txt' per sopprimere la stampa di linee nuove e non modificate. –

3

Nel caso i file non sarebbero stati ancora ordinati, è possibile utilizzare:

comm -23 <(sort a.txt) <(sort b.txt) 
Problemi correlati