Manejo de 3 archivos usando awk

9

Considere los siguientes archivos:

file1:

boo,8,1024
foo,7,2048

file2:

foo,0,24,154
noo,0,10,561

file3:

24,154,7,1024,0

Lo que necesito es ir a File1 y verificar si $2==7; si es cierto, tomar $1, $2y $3de archivo1 ; ahora tengo que comparar si $1desde File1 igual a $1desde File2 ; si es cierto, tengo que tomar $3y $4de archivo2 , que no existe en archivo1 , entonces tengo que ir a File3 y comprobar si $1de File3 es igual al $3de archivo2 , y $2desde File3 es igual al $4de archivo2 ; en caso afirmativo, entonces tengo que verificar si $2desde File1es igual al $3de File3 , a continuación, si esta condición es verdadera, tengo que comparar $3de archivo1 con el $4de File3 , si $3de archivo1 es más $4de File3 .

Intenté el siguiente script:

cat [file1] [file2] [file3] | 
awk -F, 
'{if(NF==3)
    {if($2==7){a[$1]=$1; b[$1]=$2; c[$1]=$3}
    }else
        {if(NF==4){if(a[$1]==$1){d[$3]=$3; e[$4]=$4}
                  }else
                        {if(NF==5){if(d[$1]==$1 && e[$2]==$2){print a[$1], b[$1], c[$1], d[$1]}}
                        }
                  }

  }'

La salida deseada es:

foo,7,2048,24,154,1024
Eng7
fuente

Respuestas:

9

Eso funcionó para mí:

awk -F, 'FNR==1{++f} \
  f==1 && $2==7 {a1[$1]++; a2[$2]=$3; o=$0} \
  f==2 && a1[$1] {o=o","$3","$4; a3[$3]=$4} \
  f==3 && a3[$1] && $2==a3[$1] && a2[$3] && $4<a2[$3] {print o}' \
file1 file2 file3

Explicacion :

  • La primera línea ( FNR==1{++f}) incrementa el índice del archivo para luego determinar en qué archivo estamos 1-3.
  • archivo1: si $2es igual7
    • llenar una matriz a1con $1como índice y a2con $2como índice y $3como valor
    • anote la ovariable (salida) con los primeros 3 campos
  • fichero2: si $1de file2los iguales $1de file1(prevously escrito en a1)
    • agregar $3y $4a la variable de salida o.
    • llenar una matriz a3con $3como índice y $4como valor.
  • archivo3: si:
    • $1es igual a file2s $3(índice de a3)
    • $2es igual a file2s $4(valor de a3)
    • $3es igual a file1s $2(índice de a2)
    • $4es inferior a file1s $3(valor de a2)
  • entonces:
    • imprime el valor de o.
caos
fuente
¿Hay necesidad de barra invertida (aparte de la última)? ¿Qué tal BEGINFILE (en lugar de FNR == 1)?
Archemar
@Archemar BEGINFILE y ENDFILE son extensiones de gawk y las barras invertidas se pueden eliminar, las inserté, para una mejor legibilidad: puedes escribir todo esto en una sola línea, pero no se vería bien
caos
@chaos, gracias, pero desafortunadamente siempre devuelve nulo.
Eng7
@ Azizieh7 Lo probé con mawk y gawk con tus 3 archivos de ejemplo de entrada. Para mí funcionó. ¿Utiliza diferentes archivos de entrada o codificaciones / saltos de línea?
caos
@chaos, hay diferentes saltos de línea en el archivo 3, pero uso tr -d '\ 015' para superar esto.
Eng7
1

Solución TXR:

@(repeat)
@id,@val0,@val1
@  (next)
@  (skip)
@id,@nil,@val2,@val3
@  (next)
@val2,@val3,@val0,@val4,@val5
@  (require (< (int-str val4) (int-str val1)))
@  (output)
@id,@val0,@val1,@val2,@val3,@val4
@  (end)
@(end)

Correr:

$ txr join.txr file1 file2 file3
foo,7,2048,24,154,1024

Pero el astuto observador notará que el 7 no se ha especificado en ninguna parte del código, ¡solo aparece en la salida! Esto se debe a que el código en realidad está avanzando por todos los registros file1e imprime todas las combinaciones que cumplen con las coincidencias y restricciones . El único en los datos de muestra es el que tiene val0ser 7.

Si se encontraran más combinaciones, podría limitarse solo a 7una como esta:

$ txr -Dval0=7 join.txr file1 file2 file3
foo,7,2048,24,154,1024

# how about 6?
$ txr -Dval0=6 join.txr file1 file2 file3
# no output

El lenguaje de extracción de patrones TXR proporciona aquí una gran coincidencia de patrones con referencias implícitas a través de la repetición de nombres de variables, que abarcan varios archivos, con patrones de extracción de varias líneas y restricciones no textuales, además de efectos secundarios integrados como salida, etc. .

La solución Awk aceptada tradujo cuidadosamente la awkmacro TXR Lisp :

(awk (:begin (set fs "," ofs ","))
     (:let o (a1 (hash :equal-based)) (a2 (hash)) (a3 (hash)))
     (t (mf [orf int-str identity])) ;; map those fields to integers, which can be
     ((and (= arg 1) (= [f 1] 7)) (inc [a1 [f 0] 0])
                                  (set [a2 [f 1]] [f 2])
                                  (set o rec))
     ((and (= arg 2) [a1 [f 0]]) (set o `@o,@[f 2],@[f 3]`)
                                 (set [a3 [f 2]] [f 3]))
     ((and (= arg 3)
           [a3 [f 0]]
           (= [f 1] [a3 [f 0]])
           [a2 [f 2]]
           (< [f 3] [a2 [f 2]])) (prn o)))

Correr:

$ txr awkit.tl file1 file2 file3
foo,7,2048,24,154

La ,1024parte requerida en la salida está ausente; el "Awk Classic" original tiene este comportamiento.

Kaz
fuente