Foros del Web » Administración de Sistemas » Unix / Linux »

Hacer JOIN de dos ficheros mediante Shell Script/AWK

Estas en el tema de Hacer JOIN de dos ficheros mediante Shell Script/AWK en el foro de Unix / Linux en Foros del Web. Hola a todos: tengo la necesidad de hacer un cruce entre 2 ficheros mediante un determinado campo y una determinada lógica de manera que si ...
  #1 (permalink)  
Antiguo 21/01/2015, 11:50
 
Fecha de Ingreso: enero-2008
Mensajes: 2
Antigüedad: 16 años, 9 meses
Puntos: 0
Hacer JOIN de dos ficheros mediante Shell Script/AWK

Hola a todos:

tengo la necesidad de hacer un cruce entre 2 ficheros mediante un determinado campo y una determinada lógica de manera que si la información cruza pueda rescatar el valor del fichero 2 y ponerlo en el fichero 1. El caso esque esto sabría hacerlo perfectamente mediante una query de SQL en ORACLE pero hacerlo mediante un .sh se me escapa, creo que lo mejor para tratar ficheros es utilizar AWK, pero no lo tengo del todo claro. Os pongo un ejemplo mas o menos gráfico de lo que necesito, tengo 2 ficheros, los cuales no tienen separador de campo pero sí una delimitación fija que conozco :

fichero1.dat

25742telefono1mac1577S
64523telefono2mac2655N

fichero2.dat

mac1valor15
mac2valor28

necesitaría cruzar el valor 'mac1' del fichero 1 contra el valor 'mac1' del fichero 2 y si cruza sustituir el valor del fichero 1 por otro campo del fichero 2, quedando finalmente algo así:

fichero1

25742telefono1valor1577S
64523telefono2mac2655N

el segundo registro no cambia ya que no cumple la lógica en la que se dice que el último campo del registro debe ser='S'.

Agredecería me echárais un cable.
Un saludo
-bertxo-
  #2 (permalink)  
Antiguo 22/01/2015, 08:02
AlvaroG
Invitado
 
Mensajes: n/a
Puntos:
Respuesta: Hacer JOIN de dos ficheros mediante Shell Script/AWK

Bueno, no has puesto los requisitos ordenados, pero creo que se entiende:
"Si un registro del fichero1 termina con S, y existe una línea en fichero2 que comience con los caracteres (x, x+n) del registro, sustituir en él dichos caracteres por los caracteres (n, hasta fin de línea) de la línea del fichero2".

Sería bastante más fácil si los campos estuviesen delimitados por espacios, en vez de caracteres. Para separar campos por caracteres se usa 'cut'. Se me ocurre esta forma, que no está mal si el archivo no es gigante:

Código BASH:
Ver original
  1. cp fichero1.dat fichero1.dat.original
  2. while read linea; do
  3.     # obtenemos los pares (clave, valor) del fichero2
  4.     K=$(echo $linea | cut -c1-4)
  5.     V=$(echo $linea | cut -c5-)
  6.     sed -i 's/^\(.*\)'$K'\(.*\)S$/\1'$V'\2S/g' fichero1.dat # sustituimos todas las líneas de fichero1 que contengan la clave y terminen en S
  7. done < fichero2.dat

El problema de esta solución es que lee y escribe fichero1 por cada línea de fichero2, con lo que si hablamos de decenas de miles de líneas, los tiempos de lectura+escritura del archivo pueden terminar siendo significativos.

Existe la posibilidad de leer todos los pares clave-valor de una vez, y luego hacer la sustitución línea por línea vía AWK, ya que awk soporta matrices asociativas. Otros lenguajes de programación, como Perl o Python, son una mejor opción si el programa tiene que hacer cosas más complejas.

Volviendo al tema de los campos delimitados por espacios, si tus archivos fuesen así:
Código BASH:
Ver original
  1. 25742telefono1 mac1 577S
  2. 64523telefono2 mac2 655N
  3.  
  4. mac1 valor15
  5. mac2 valor28
El comando join bastaría para resolver el problema (excepto, claro, por el asunto de que termine en S...):

# unir las líneas por el 2do campo del fichero1, y el 1er campo del fichero2, luego imprimir el primer campo del primer fichero, el segundo del segundo fichero, y el tercer campo del primer fichero.
Código BASH:
Ver original
  1. $ join -1 2 -2 1 -o 1.1 2.2 1.3 fichero1.dat fichero2.dat
  2. 25742telefono1 valor15 577S
  3. 64523telefono2 valor28 655N

Etiquetas: ficheros, join, mediante, shell
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 09:58.