Para esto fue diseñado 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 dos primeros campos en la c
matriz. 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 verdadera, la línea se imprimirá.
Alternativamente, ya que etiquetaste con Perl:
perl -e 'open(A, "file2"); while(<A>){/.+?\|[^|]+/ && $k{$&}++};
while(<>){/.+?\|[^|]+/ && do{print if defined($k{$&})}}' file1
Explicación
Se abrirá la primera línea file2
, lea todo hasta el segundo |
( .+?\|[^|]+
) y guárdelo ( $&
es el resultado del último operador del partido) en el %k
hash.
La segunda línea procesa el archivo1, usa la misma expresión regular para extraer las dos primeras columnas e imprimir la línea si esas columnas están definidas en el %k
hash.
Ambos enfoques anteriores necesitarán mantener las 2 primeras columnas del archivo2 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.