Fusiona 2 files basados ​​en todos los valores de la primera columna del primer file

Necesito fusionar debajo de 2 files:

  • file1 :

TABLAS REF-IO HEAD-IO DIFF-IO
testing 200 500 -300
examen 2 3 -1
final 2 1 1
correo 4 2 2
TOTAL 208 506 -298

  • file2 :

TABLAS REF-SELECT HEAD-SELECT DIFF-SELECT
testing 5 7 -2
juego 3 3 0
examen 0 7 -7
final 12 6 6
TOTAL 20 23 -3

file fusionado debe ser como se muestra a continuación:

TABLAS REF-IO HEAD-IO DIFF-IO REF-SELECT HEAD-SELECT DIFF-SELECT
testing 200 500 -300 5 7 -2
examen 2 3 -1 0 7 -7
final 2 1 1 12 6 6
correo 4 2 2 0 0 0
TOTAL 208 506 -298 20 23 -3

 awk ' NR==FNR {vals[$1] = $2 " " $3 " " $4; next} !($1 in vals) {vals[$1] = "0 0 0"} {$(NF+1) = vals[$1]; print} ' file2 file1 
 TABLES REF-IO HEAD-IO DIFF-IO REF-SELECT HEAD-SELECT DIFF-SELECT test 200 500 -300 5 7 -2 exam 2 3 -1 0 7 -7 final 2 1 1 12 6 6 mail 4 2 2 0 0 0 TOTAL 208 506 -298 20 23 -3 

He aquí cómo hacerlo con join y preservar el order de las líneas, los encabezados, los pies de página, etc.

 join -1 2 -2 1 -a 1 -e 0 -o 1.1,1.2,1.3,1.4,1.5,2.2,2.3,2.4 \ <(sort -k2,2 <(nl -ba -nrz file1)) <(sort -k1,1 file2) | \ sort -k1,1n | cut -d\ -f2- 

resultado:

 TABLES REF-IO HEAD-IO DIFF-IO REF-SELECT HEAD-SELECT DIFF-SELECT test 200 500 -300 5 7 -2 exam 2 3 -1 0 7 -7 final 2 1 1 12 6 6 mail 4 2 2 0 0 0 TOTAL 208 506 -298 20 23 -3 

Cómo funciona:

nl -ba -nrz file1 numera las líneas en file1 , luego la salida se sort en el 2do campo; file2 también se sort en el primer campo y los resultados se join en el segundo campo desde la primera input y el primer campo desde la segunda input, reemplazando los campos de input faltantes con 0 :

 000003 exam 2 3 -1 0 7 -7 000004 final 2 1 1 12 6 6 000005 mail 4 2 2 0 0 0 000001 TABLES REF-IO HEAD-IO DIFF-IO REF-SELECT HEAD-SELECT DIFF-SELECT 000002 test 200 500 -300 5 7 -2 000006 TOTAL 208 506 -298 20 23 -3 

esto se ordera en el primer campo con sort -k1,1n para restaurar el order de línea y luego cut -d\ -f2- elimina los numbers de línea. Usted podría embellecerlo aún más con una column por ejemplo .... | column -t .... | column -t :

 TABLES REF-IO HEAD-IO DIFF-IO REF-SELECT HEAD-SELECT DIFF-SELECT test 200 500 -300 5 7 -2 exam 2 3 -1 0 7 -7 final 2 1 1 12 6 6 mail 4 2 2 0 0 0 TOTAL 208 506 -298 20 23 -3 

Este script debería funcionar:

 touch resultFile while read f; do header1=$(echo $f | awk '{print $1;}'); values1=$(echo $f | awk -F "$header1 " '{print $NF;}'); while read g; do header2=$(echo $g | awk '{print $1;}'); values2=$(echo $g | awk -F "$header2 " '{print $NF;}'); if [ $header1 = $header2 ]; then echo "$header1 $values1 $values2" >> resultFile fi done < file2 done < file1 

Los encabezados deben ser únicos, de lo contrario solo se fusionará la última línea encontrada.

PD: he considerado que el encabezado "mail" no debería estar presente en el resultado ya que no está presente en ambos files, como "juego" (en tu ejemplo "correo" está presente pero no es "juego").

En caso de que se lo pregunte, es posible hacer esto con join , aunque el order de las líneas no se conserva:

 ( join <(head -n1 file1) <(head -n1 file2) join -a 1 -e 0 -o '0 1.2 1.3 1.4 2.2 2.3 2.4' \ <(sed -n 2,5p file1 | sort) \ <(sed -n 2,5p file2 | sort) join <(tail -n1 file1) <(tail -n1 file2) ) 

Salida:

 TABLES REF-IO HEAD-IO DIFF-IO REF-SELECT HEAD-SELECT DIFF-SELECT exam 2 3 -1 0 7 -7 final 2 1 1 12 6 6 mail 4 2 2 0 0 0 test 200 500 -300 5 7 -2 TOTAL 208 506 -298 20 23 -3