GNU/Linux >> Tutoriales Linux >  >> Linux

¿Comparar dos columnas de diferentes archivos e imprimir si coincide?

Estoy usando Solaris 10 y, por lo tanto, las opciones de grep que involucran -f no funcionan.

Tengo dos archivos separados por tuberías:

archivo1:

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

archivo 2:

abc|123|
kumar|pki|
cab|234

Me gustaría comparar las dos primeras columnas del archivo 2 con el archivo 1 (buscar en todo el contenido del archivo 1 en las dos primeras columnas) si coinciden, imprima la línea coincidente del archivo 1. Luego busque la segunda línea del archivo 2 y así sucesivamente.

Salida esperada:

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

Los archivos que tengo son enormes, contienen unas 400.000 líneas, por lo que me gustaría que la ejecución fuera rápida.

Respuesta aceptada:

Esto es para lo que se diseñó awk:

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

Explicación

  • -F'|' :establece el separador de campo en | .
  • NR==FNR :NR es el número de línea de entrada actual y FNR el número de línea del archivo actual. Los dos serán iguales solo mientras se lee el primer archivo.
  • c[$1$2]++; next :si este es el primer archivo, guarde los primeros dos campos en el c formación. Luego, salte a la siguiente línea para que esto solo se aplique en el primer archivo.

  • c[$1$2]>0 :el bloque else solo se ejecutará si este es el segundo archivo, por lo que verificamos si los campos 1 y 2 de este archivo ya se han visto (c[$1$2]>0 ) y si lo han sido, imprimimos la línea. En awk , la acción predeterminada es imprimir la línea, por lo que si c[$1$2]>0 es verdadero, la línea se imprimirá.

Alternativamente, ya que etiquetó con Perl:

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

Explicación

La primera línea abrirá file2 , lee todo hasta el 2° | (.+?|[^|]+ ) y guárdelo (el $& es el resultado del último operador de coincidencia) en el %k hash.

La segunda línea procesa el archivo 1, usa la misma expresión regular para extraer las dos primeras columnas e imprime la línea si esas columnas están definidas en %k hash.

Ambos enfoques anteriores deberán contener las 2 primeras columnas de file2 en la memoria. Eso no debería ser un problema si solo tiene unos cientos de miles de líneas, pero si lo es, podría hacer algo como

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

Pero eso será más lento.

Relacionado:¿Copiar todos los programas y archivos instalados en un disco duro (que tiene Windows 7 de 32 bits) y clonarlos/transferirlos a otra computadora que tenga Windows 7 de 64 bits?
Linux
  1. Compara archivos y carpetas gráficamente en Linux con Meld

  2. ¿Imprimir líneas entre (y excluyendo) dos patrones?

  3. Lum - ¿Combinar columnas de dos archivos separados?

  4. Cómo comparar el contenido de dos tarball

  5. ¿Cómo redirigir stderr y stdout a diferentes archivos en la misma línea en el script?

Cómo eliminar archivos y directorios usando la línea de comandos de Linux

Cómo comparar y fusionar archivos de texto en Linux

Cómo comparar y fusionar archivos de texto en Linux (parte 2)

Cómo comparar dos archivos en la terminal de Linux

Compare dos archivos en Linux:use diff, vimdiff y colordiff

Diferencia en espacios en blanco entre dos archivos en Linux