Linux/Unix Shell Scripting - Join entre dos ficheros con awk

   
Vista:

Join entre dos ficheros con awk

Publicado por bertxo (4 intervenciones) el 21/01/2015 18:39:26
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'
Valora esta pregunta
Me gusta: Está pregunta es útil y esta claraNo me gusta: Está pregunta no esta clara o no es útil
0
Responder

Join entre dos ficheros con awk

Publicado por Tom (253 intervenciones) el 21/01/2015 19:15:21
No sabría decirte cómo hacerlo en awk. Pero ... ¿ el fichero2.dat de tu ejemplo contiene muchos valores ?
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Join entre dos ficheros con awk

Publicado por bertxo (4 intervenciones) el 21/01/2015 19:25:43
Hola Tom:

sí claro, este fichero contendrá diariamente unos 20000 registros con valores distintos.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Join entre dos ficheros con awk

Publicado por Tom (253 intervenciones) el 21/01/2015 20:03:23
Tu proceso será bastante lento.
Se me ocurre que, con awk, una vez que consigas aislar los campos de cada fichero, crees un array (asociativo) de valores con el contenido del fichero2; Para esto podrías usar la función getline de awk, en el bloque BEGIN, se me ocurre.
Luego, el proceso "normal" en awk del fichero1 no tendría ya más que buscar el elemento correspondiente del array (que está en memoria).
No sé si ganas mucho con awk, ya que bash también tiene arrays asociativos ...

Básicamente la idea es, suponiendo que sea fácil separar una linea en sus campos (que por lo que cuentas, va a ser que no, mira la variable FIELDWIDTHS de awk ):
1
2
3
4
5
6
7
8
BEGIN {
  # Rellenamos un array con los datos del segundo fichero (nombre "a pelo")
  while ((getline < 'fichero2.dat') > 0) datos2[$1] = $2
}
{
  # Proceso de cada linea del primer fichero, el especificado en la linea de comando
  if( $5 == "S") { print $1 $2 datos2[$3] $4 } else { print $0 }
}

No soy experto en awk, pero algo parecido debe funcionar. Para hacerte una idea de como separar los campos de cada línea en tu caso, sin delimitador (por anchura, supongo que lo harás) mira en:

http://www.delorie.com/gnu/docs/gawk/gawk_44.html

En principio, 20000 registros es bastante, pero no tanto como para colapsar tu proceso, mientras tengas una cantidad de memoria libre razonable en la máquina.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Join entre dos ficheros con awk

Publicado por bertxo (4 intervenciones) el 21/01/2015 20:48:29
Es algo más complicado que eso ya que además de evaluar que uno de los campos del fichero sea ='S' tengo que cruzar otro de los campos del fichero1 con el del fichero2 y si cruza es cuando pongo en el fichero1 el valor del campo del fichero 2, para que se vea mejor intento ponerlo en una query en pseudo código SQL:

SELECT
fichero1.campo1
fichero1.campo2
fichero2.campo3
FROM
fichero1, fichero2
WHERE
fichero1.campo5=fichero2.campo4
AND
fichero1.campo20='S'


De esta manera solo modificaría en el fichero1 aquellos registros coincidentes en la lógica que indico.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Join entre dos ficheros con awk

Publicado por Tom (253 intervenciones) el 21/01/2015 21:17:44
¿ El problema es que podría "no cruzar" ?
En el bloque begin, tratamos fichero2, siendo fichero2.campo1 $1, fichero2.campo2 $2, ...
En el bloque general tratamos fichero1, siendo fichero1.campo1 $1, fichero1.campo2 $2, ...

1
2
3
4
5
6
7
8
9
10
11
BEGIN {
  # Rellenamos un array con los datos del segundo fichero (nombre "a pelo") 
  # El indice del array es fichero2.campo4, su valor es fichero2.campo3
  while ((getline < 'fichero2.dat') > 0) datos2[$4] = $3
}
{
  # Proceso de cada linea del primer fichero, el especificado en la linea de comando
  # Si fichero1.campo20 es S y fichero1.campo5 está en los indices del array (JOIN)
  #   imprimimos fichero2.campo3
  if( $20 == "S" && ($5 in datos2)) { print $1 $2 datos2[$5]  } else { print $1 $2 $3 }
}

Por otra parte, con awk _no_ estás modificando el fichero. Lo que se hace es imprimir el nuevo contenido.
Lo que deberás hacer es algo parecido a:

awk -f mi_script.awk fichero1.dat > fichero_resultado.dat

Además si lo que quieres en la salida es un inner join (aquí me puedo deslizar, tendría que repasar lo de los inner y outer joins) simplemente elimina el else del if.

Imaginando SQL (o algo parecido :)):
Bloque Begin:
create temp table datos2 as select campo4, campo3 from fichero2;

Bloque general:
select fichero1.campo1, fichero2.campo2, datos2.campo3
from fichero1 inner join datos2 on fichero1.campo5 = datos2.campo4
where fichero1.campo20 = 'S';
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Join entre dos ficheros con awk

Publicado por bertxo (4 intervenciones) el 22/01/2015 09:40:42
Buenos días Tom:

El campo3 del fichero 1 se alterará solo cuando coincida el campo campo5 del fichero1 con el campo4 del fichero2 en ese caso recogería el valor del campo3 del fichero2 y lo volcaría en el fichero1. Digamos que lo que quiero es sustituir el campo de un fichero por el campo de otro siempre y cuando se cumpla una lógica. El resultado del fichero final en cuanto número de registros debe ser igual al fichero1 original pero con determinadas líneas modificadas, aquellas en las que el campo de fichero1 coincida con el campo de fichero2 y que además uno de los campos del fichero1 sea='S'.

fichero1:
albertomac12345S
beatrizmac156352N

fichero2:
mac16789
mac27363
mac35398

fichero final (igual en contenido a fichero 1 pero con cruce realizado):
albertomac16789S
beatrizmac156352N

Un saludo
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar