File 1:
Connect|20130320000023|UTC|PPP|[email protected]|[email protected]|0BCBE578|
File 2:
Connect|20130320000023|UTC|PPP|[email protected]|[email protected]|0BCBE578|
Connect|20130320000025|UTC|PPP|[email protected]|[email protected]|0BCBE578|
Connect|20130320000025|UTC|PPP|[email protected]|[email protected]|0BCBE578|
Necesito encontrar registros coincidentes tanto en el Archivo 1 como en el Archivo 2 en la columna 5. Entonces, de lo anterior necesito regresar en el resultado:
Connect|20130320000025|UTC|PPP|[email protected]|[email protected]|0BCBE578|
Muchas gracias,
Respuesta1
Método n.º 1: grep y awk
Puedes usar este fragmento para hacerlo:
$ grep -f <(awk -F '|' '{print $5}' file1) file2
Connect|20130320000025|UTC|PPP|[email protected]|[email protected]|0BCBE578|
Detalles
El bit que utiliza awk
analiza el primer archivo y file1
extrae la quinta columna. Estos valores luego se usan como una lista grep
, que imprimirá cualquier línea en el segundo archivo que contenga una coincidencia.
Advertencias con este método
Este método coincidirá con cualquier aparición de la quinta columna file1
de file2
.
Método #2: Simplemente extraño
Otro enfoque que se ha utilizado en el sitio en el pasado es utilizar awk
la instalación FNR. Aquí es donde awk
se iterará sobre 2 archivos, recorriendo el segundo archivo línea por línea, para cada línea del primero.
Un enfoque como este sería suficiente. Coloque lo siguiente en un archivo cmds.awk
:
FNR == NR {
f1[$5] = $5
next
}
{ if ($5 == f1[$5]) print $0; }
Luego puede ejecutar esto de la siguiente manera:
$ awk -F '|' -f cmds.awk file1 file2
NOTA:Podrías haber usado este awk
patrón en su lugar:
FNR == NR {
f1[$5] = $5
next
}
{ if ($5 in f1) print $0; }
Ejemplo
$ awk -F '|' -f s.awk file1 file2
Connect|20130320000025|UTC|PPP|[email protected]|[email protected]|0BCBE578|
Advertencias con este método
Este enfoque solo puede manejar una única instancia de cada dirección de correo electrónico de file1
. Entonces, si hay 2 líneas que tienen el mismo valor para la quinta columna, no se podrán distinguir entre ellas. Sin embargo, esto parece aceptable dados sus requisitos en el OP.
Unirse y ordenar
También puedes hacer esto usando join
y sort
.
$ join -t '|' -j 5 <(sort -k5,5 file2) <(sort -k5,5 file1) | sed 's/||.*//'
Esto utilizará el separador |
y unirá los archivos ordenados en la quinta columna. Este enfoque imprime las coincidencias de ambos file1
y file2
, por lo que utilizamos sed
para cortar la segunda coincidencia del final.
Ejemplo
$ join -t '|' -j 5 <(sort -k5,5 file2) <(sort -k5,5 file1) | sed 's/||.*//'
[email protected]|Connect|20130320000025|UTC|PPP|[email protected]|0BCBE578
Respuesta2
Haría todo en Perl:
$ perl -F'\|' -ane '$k{$F[4]}++; print if $k{$F[4]}>1' file1 file2
Connect|20130320000025|UTC|PPP|[email protected]|[email protected]|0BCBE578|
-a
activa la división automática de campos en la matriz@F
.-F'\|'
establece el delimitador de campo para-a
en|
.- Para cada línea procesada, guarde el quinto campo (los índices de matriz comienzan en
0
Perl) como una clave hash ($k{$F[4]}++
e incremente su valor en uno. La segunda vez que se vea un campo, ese valor será 2. - El script procesará cada línea de ambos archivos (
file1
antesfile2
) e imprimirá la línea si el quinto campo se ha visto antes, es decir, si$k{$F[4]}
es mayor que uno.
Esto supone que no se repite ninguna quinta columna dentro delmismoarchivo. Si este no es el caso y algunas columnas pueden estar duplicadas en el mismo archivo, utilice esto en su lugar:
perl -e 'open(A,"$ARGV[0]"); while(<A>){@F=split(/\|/);$k{$F[4]}++;}
open(B,"$ARGV[1]"); while(<B>){@F=split(/\|/); print if $k{$F[4]}
}' file1 file2
Respuesta3
Si los tamaños de los archivos son comparables, la solución óptima essort
ambos archivos por la columna que le interesa y luegojoin
ellos por esa columna. Si los tamaños de los archivos son N
y M
entonces el tiempo de ejecución asintótico es O(N*log(N)+M*log(M))
.
Si uno de los archivos es mucho más pequeño que el otro, entonces la O(N*M)
solución en las otras respuestas es mejor.