GNU/Linux >> Linux Esercitazione >  >> Linux

Confronta due colonne di file diversi e stampa se corrisponde?

Sto usando Solaris 10 e quindi le opzioni grep che coinvolgono -f non funzionano.

Ho due file separati da pipe:

file1:

abc|123|BNY|apple|
cab|234|cyx|orange|
def|kumar|pki|bird|

file 2:

abc|123|
kumar|pki|
cab|234

Vorrei confrontare le prime due colonne di file2 con file1 (cerca l'intero contenuto di file1 nelle prime due colonne) se corrispondono, stampa la riga corrispondente di file1. Quindi cerca la seconda riga del file 2 e così via.

Uscita prevista:

abc|123|BNY|apple|
cab|234|cyx|orange|

I file che ho sono enormi, contengono circa 400.000 righe, quindi vorrei velocizzare l'esecuzione.

Risposta accettata:

Questo è ciò per cui awk è stato progettato:

$ awk -F'|' 'NR==FNR{c[$1$2]++;next};c[$1$2] > 0' file2 file1
abc|123|BNY|apple|
cab|234|cyx|orange|

Spiegazione

  • -F'|' :imposta il separatore di campo su | .
  • NR==FNR :NR è il numero di riga di input corrente e FNR il numero di riga del file corrente. I due saranno uguali solo durante la lettura del primo file.
  • c[$1$2]++; next :se questo è il 1° file, salva i primi due campi nel c Vettore. Quindi, passa alla riga successiva in modo che venga applicata solo al primo file.

  • c[$1$2]>0 :il blocco else verrà eseguito solo se questo è il secondo file quindi controlliamo se i campi 1 e 2 di questo file sono già stati visti (c[$1$2]>0 ) e se lo sono stati, stampiamo la riga. In awk , l'azione predefinita è stampare la riga così se c[$1$2]>0 è vero, la riga verrà stampata.

In alternativa, poiché hai taggato con Perl:

perl -e 'open(A, "file2"); while(<A>){/.+?|[^|]+/ && $k{$&}++};
         while(<>){/.+?|[^|]+/ && do{print if defined($k{$&})}}' file1

Spiegazione

La prima riga aprirà file2 , leggi tutto fino al 2° | (.+?|[^|]+ ) e salvarlo (il $& è il risultato dell'ultimo operatore di corrispondenza) nel %k hash.

La seconda riga elabora file1, usa la stessa espressione regolare per estrarre le prime due colonne e stampare la riga se quelle colonne sono definite in %k hash.

Entrambi gli approcci precedenti dovranno contenere le prime 2 colonne di file2 in memoria. Non dovrebbe essere un problema se hai solo poche centinaia di migliaia di righe, ma se lo è, potresti fare qualcosa del tipo

cut -d'|' -f 1,2 file2 | while read pat; do grep "^$pat" file1; done

Ma sarà più lento.

Correlati:copiare tutti i programmi e i file installati su un disco rigido (che ha Windows 7 a 32 bit) e clonarlo/trasferirlo su un altro computer che ha Windows 7 a 64 bit?
Linux
  1. Stampa linee tra (ed escludendo) due motivi?

  2. Stampa linee tra (e inclusi) due motivi?

  3. Stampa due file in due colonne?

  4. Stampa la riga di corrispondenza e l'ennesima riga dalla riga di corrispondenza?

  5. Lum:unire colonne da due file separati?

Come rimuovere file e directory utilizzando la riga di comando di Linux

Come confrontare e unire file di testo su Linux

Come confrontare e unire file di testo su Linux (parte 2)

Come confrontare due file nel terminale Linux

Confronta due file in Linux – Usando diff, vimdiff e colordiff

Differenza negli spazi bianchi tra due file su Linux