Gestion de 3 fichiers avec awk

9

Pensez aux fichiers suivants:

file1:

boo,8,1024
foo,7,2048

file2:

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

file3:

24,154,7,1024,0

Ce dont j'ai besoin, c'est d'aller dans File1 et de vérifier si $2==7; si cela est vrai, prendre $1, $2et $3de Fichier1 ; maintenant je dois comparer si $1de Fichier1 égal à $1partir Fichier2 ; si c'est vrai, je dois prendre $3et $4de File2 qui n'existent pas dans File1 , alors je dois aller à File3 et vérifier si $1de File3 est égal à $3de File2 , et $2de File3 est égal à $4de File2 ; si oui, je dois vérifier si $2depuis File1est égale à $3partir Fichier3 , alors si cette condition est vrai, je dois comparer $3de Fichier1 avec $4de Fichier3 , si $3de Fichier1 est plus $4de Fichier3 .

J'ai essayé le script suivant:

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 sortie souhaitée est:

foo,7,2048,24,154,1024
Eng7
la source

Réponses:

9

Cela a fonctionné pour moi:

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

Explication :

  • La première ligne ( FNR==1{++f}) incrémente l'index du fichier pour déterminer plus tard dans quel fichier nous sommes 1-3.
  • file1: si $2égal7
    • remplir un tableau a1avec $1comme index et a2avec $2comme index et $3comme valeur
    • écrire la ovariable (sortie) avec les 3 premiers champs
  • fichier2: si $1d' file2égal à égal $1de file1(prevously écrit a1)
    • ajouter $3et $4à la variable de sortie o.
    • remplir un tableau a3avec $3comme index et $4comme valeur.
  • fichier3: si:
    • $1est égal à file2s $3(index de a3)
    • $2est égal à file2s $4(valeur de a3)
    • $3est égal à file1s $2(index de a2)
    • $4est inférieur à file1s $3(valeur de a2)
  • puis:
    • imprimer la valeur de o.
le chaos
la source
Y a-t-il un besoin de barre oblique inverse (à part la dernière)? que diriez-vous BEGINFILE (au lieu de FNR == 1)?
Archemar
@Archemar BEGINFILE et ENDFILE sont des extensions gawk et les barres obliques inverses peuvent toutes être supprimées, je les ai insérées, pour une meilleure lisibilité: vous pouvez écrire tout cela sur une seule ligne, mais ce ne serait pas beau
chaos du
@chaos, merci, mais malheureusement, il retourne toujours null.
Eng7
@ Azizieh7 Je l'ai testé avec mawk et gawk avec vos 3 fichiers d'exemple d'entrée. Pour moi, cela a fonctionné. Utilisez-vous différents fichiers d'entrée ou encodages / sauts de ligne?
chaos
@chaos, il y a différents sauts de ligne dans file3, mais j'utilise tr -d '\ 015' pour surmonter cela.
Eng7
1

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

Courir:

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

Mais l'observateur astucieux notera que le 7 n'a été spécifié nulle part dans le code, n'apparaissant que dans la sortie! En effet, le code parcourt tous les enregistrements file1et imprime toutes les combinaisons qui correspondent aux correspondances et à la contrainte . Le seul des exemples de données est celui avec l' val0être 7.

S'il y avait plus de combinaisons trouvées, cela pourrait être limité à 7celle comme celle-ci:

$ 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

Le langage d'extraction de modèle TXR fournit ici une grande correspondance de modèle avec des références arrière implicites via la répétition de noms de variables, couvrant plusieurs fichiers, avec des modèles d'extraction sur plusieurs lignes et des contraintes non textuelles, ainsi que des effets secondaires intégrés comme la sortie, etc. .

La solution Awk acceptée a soigneusement traduit 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)))

Courir:

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

La ,1024partie requise dans la sortie est manquante; le "Awk Classic" d'origine a ce comportement.

Kaz
la source