Gestire 3 file usando awk


9

Prendi in considerazione i seguenti file:

file1:

boo,8,1024
foo,7,2048

file2:

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

file3:

24,154,7,1024,0

Ciò di cui ho bisogno è andare su File1 e verificare se $2==7; se è vero, prendere $1, $2e $3da File1 ; ora devo confrontare se $1da File1 uguale a $1da File2 ; se vero, devo prendere $3e $4da File2 che non esiste in File1 , quindi devo andare su File3 e controllare se $1da File3 è uguale a $3da File2 e $2da File3 è uguale a $4da File2 ; se sì, allora devo controllare se $2da File1è uguale a $3da File3 , quindi se questa condizione è vera, devo confrontare $3da File1 con $4da File3 , se $3da File1 è più che $4da File3 .

Ho provato il seguente 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]}}
                        }
                  }

  }'

L'output desiderato è:

foo,7,2048,24,154,1024

Risposte:


9

Ha funzionato per me:

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

Spiegazione :

  • La prima riga ( FNR==1{++f}) incrementa l'indice del file per determinare in seguito in quale file siamo 1-3.
  • file1: se $2uguale7
    • riempire una matrice a1con $1come indice e a2con $2come indice e $3come valore
    • annotare la ovariabile (output) con i primi 3 campi
  • file2: se $1di file2eguali $1di file1(prevously scritto in a1)
    • append $3e $4alla variabile di output o.
    • riempire una matrice a3con $3come indice e $4come valore.
  • file3: se:
    • $1è uguale a file2s $3(indice di a3)
    • $2è uguale a file2s $4(valore di a3)
    • $3è uguale a file1s $2(indice di a2)
    • $4è inferiore a file1s $3(valore di a2)
  • poi:
    • stampa il valore di o.

C'è bisogno di una barra rovesciata (a parte l'ultima)? che ne dici di BEGINFILE (invece di FNR == 1)?
Archemar,

@Archemar BEGINFILE ed ENDFILE sono estensioni gawk e le barre rovesciate possono essere rimosse, le ho inserite, per una migliore leggibilità: puoi scrivere l'intera cosa in una sola riga, ma non sarebbe bello
caos

@chaos, grazie, ma purtroppo restituisce sempre null.
Eng7

@ Azizieh7 L'ho provato con mawk e gawk con i tuoi 3 file di esempio di input. Per me ha funzionato. Usi diversi file di input o codifiche / interruzioni di riga?
caos,

@chaos, ci sono diverse interruzioni di riga in file3, ma io uso tr -d '\ 015' per ovviare a questo.
Eng7

1

Soluzione 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)

Correre:

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

Ma l'osservatore astuto noterà che il 7 non è stato specificato da nessuna parte nel codice, apparendo solo nell'output! Questo perché il codice sta effettivamente marciando attraverso tutti i record file1e stampa tutte le combinazioni che soddisfano le corrispondenze e il vincolo . L'unico nei dati di esempio è quello con val0essere 7.

Se fossero state trovate più combinazioni, potrebbe essere limitata a 7quella come questa:

$ 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

Il linguaggio di estrazione dei pattern TXR fornisce qui una grande corrispondenza dei pattern con riferimenti secondari impliciti attraverso la ripetizione di nomi di variabili, che si estende su più file, con pattern di estrazione multilinea e vincoli non testuali, oltre a effetti collaterali incorporati come output e così via .

La soluzione Awk accettata ha tradotto attentamente 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)))

Correre:

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

La ,1024parte richiesta nell'output è mancante; l'originale "Awk Classic" ha questo comportamento.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.