2016-01-06 39 views
6

Ho un file1, che ha poche righe (decine) e un file2 molto più lungo (~ 500.000 righe). Le linee in ogni file non sono identiche, sebbene esista un sottoinsieme di campi identici. Voglio prendere i campi 3-5 da ogni riga in file1 e cercare file2 per lo stesso modello (solo quei tre campi, nello stesso ordine - in file2, rientrano nei campi 2-4). Se viene trovata una corrispondenza, desidero eliminare la riga corrispondente da file1.awk/sed/grep per eliminare righe corrispondenti ai campi in un altro file

esempio, file1:

2016-01-06T05:38:31 2016-01-06T05:23:33 2016006 120E A TM Current 
2016-01-06T07:34:01 2016-01-06T07:01:51 2016006 090E B TM Current 
2016-01-06T07:40:44 2016-01-06T07:40:41 2016006 080E A TM Alt 
2016-01-06T07:53:50 2016-01-06T07:52:14 2016006 090E A TM Current 
2016-01-06T08:14:45 2016-01-06T08:06:33 2016006 080E C TM Current 

file2:

2016-01-06T07:35:06.87 2016003 100E C NN Current 0 
2016-01-06T07:35:09.97 2016003 100E B TM Current 6303 
2016-01-06T07:36:23.12 2016004 030N C TM Current 0 
2016-01-06T07:37:57.36 2016006 090E A TM Current 399 
2016-01-06T07:40:29.61 2016006 010N C TM Current 0 

... (e per 500.000 linee)

Quindi, in questo caso, voglio cancellare la quarta linea di file1 (sul posto).

Di seguito trova le righe voglio eliminare:

grep "$(awk '{print $3,$4,$5}' file1)" file2 

Così una soluzione può essere quella di un tubo da questa a sed, ma sono poco chiaro come impostare un modello di corrispondenza in sed da un ingresso in filodiffusione. E la ricerca online suggerisce che awk può probabilmente fare tutto questo (o forse sed, o qualcos'altro), chiedendosi come sarebbe una soluzione pulita.

Inoltre, la velocità è un po 'importante perché altri processi possono tentare di modificare i file mentre questo è in corso (so che questo potrebbe presentare più complicazioni ...). Le corrispondenze si trovano generalmente alla fine del file2, non all'inizio (nel caso in cui ci sia un modo per cercare file2 dal basso verso l'alto).

+0

pluse-uno per il problema descritto in modo eccellente. Continua a postare e buona fortuna. – shellter

risposta

4
$ awk 'NR==FNR{file2[$2,$3,$4]; next} !(($3,$4,$5) in file2)' file2 file1 
2016-01-06T05:38:31 2016-01-06T05:23:33 2016006 120E A TM Current 
2016-01-06T07:34:01 2016-01-06T07:01:51 2016006 090E B TM Current 
2016-01-06T07:40:44 2016-01-06T07:40:41 2016006 080E A TM Alt 
2016-01-06T08:14:45 2016-01-06T08:06:33 2016006 080E C TM Current 

Il fatto che file2 contiene 500.000 linee dovrebbe essere un problema per la memoria awk wrt o velocità di esecuzione - dovrebbe completare in circa 1 secondo o meno anche nel caso peggiore.

Con qualsiasi comando UNIX, per sovrascrivere il file originale basta fare:

cmd file > tmp && mv tmp file 

quindi in questo caso:

awk '...' file2 file1 > tmp && mv tmp file1 
+0

Grazie. Vedo come funziona, ed è piuttosto veloce. Stavo cercando di farlo al contrario, leggendo file1 in un array (dal momento che è molto più piccolo), ma non sono chiaro come stampare righe da file1, che non corrispondono. – trid3

+0

Quindi ora sai che leggere file1 in un array è l'approccio sbagliato, giusto? Ciò farebbe risparmiare memoria, ma sarebbe necessario eseguire il ciclo dell'intero file1 array una volta per ogni riga del file 2, in modo da aumentare il tempo richiesto dallo script per eseguire un fattore di moltiplicazione del numero di righe in file1. –

+0

Ad es. Qualcosa del genere: awk 'NR == FNR {file1 [$ 3, $ 4, $ 5]; next}! (($ 2, $ 3, $ 4) nel file1) {print XX} 'file1 file2. Cosa potrebbe essere XX? Se potessimo semplicemente grep file1 for ($ 2, $ 3, $ 4) (ora che sappiamo che non esiste nel file2), e stamparlo, questo sarebbe il trucco. – trid3

1

Si possono trovare non corrispondenti linee in file1:

$ grep -v -F -f <(awk '{ print $3,$4,$5 }' file2) file1 
2016-01-06T05:38:31 2016-01-06T05:23:33 2016006 120E A TM Current 
2016-01-06T07:34:01 2016-01-06T07:01:51 2016006 090E B TM Current 
2016-01-06T07:40:44 2016-01-06T07:40:41 2016006 080E A TM Alt 
2016-01-06T08:14:45 2016-01-06T08:06:33 2016006 080E C TM Current 

Proprio reindirizzare questo da qualche parte e sovrascrivere file1 dopo.

+0

Assolutamente NON farlo perché, anche se può produrre l'output atteso dato questo input di esempio, in generale si otterranno false corrispondenze a seconda del contenuto dei due file poiché è greping per il contenuto di file2 su tutta la linea di file1 invece che solo nei campi di destinazione di file1. –