Traitement de deux fichiers avec awk


9

J'ai lu Comparer deux fichiers en utilisant Unix et Awk . C'est vraiment intéressant. Je l'ai lu et testé, mais je ne peux pas le comprendre complètement et l'utiliser dans d'autres cas.

J'ai deux fichiers. file1a un champ et l'autre a 16 champs. Je veux lire les éléments de file1 et les comparer avec le 3ème champ de file2. S'il y avait une correspondance pour chaque élément, je additionne la valeur du champ 5 po file2. Par exemple:

fichier 1

1
2
3

fichier 2

2 2 2 1 2
3 6 1 2 4 
4 1 1 2 3
6 3 3 3 4 

Pour l'élément 1 dans file1Je veux ajouter des valeurs dans le champ 5 file2où la valeur du champ 3 est 1. Et faire de même pour les éléments 2 et 3 dans file1. La sortie pour 1 est (3 + 4 = 7) et pour 2 est 2 et pour 3 est 4.

Je ne sais pas comment l'écrire avec awk.

Réponses:


20

Voici une façon. Je l'ai écrit comme un script awk afin que je puisse ajouter des commentaires:

#!/usr/local/bin/awk -f

{
    ## FNR is the line number of the current file, NR is the number of 
    ## lines that have been processed. If you only give one file to
    ## awk, FNR will always equal NR. If you give more than one file,
    ## FNR will go back to 1 when the next file is reached but NR
    ## will continue incrementing. Therefore, NR == FNR only while
    ## the first file is being processed.
    if(NR == FNR){
      ## If this is the first file, save the values of $1
      ## in the array n.
      n[$1] = 0
    }
    ## If we have moved on to the 2nd file
    else{
      ## If the 3rd field of the second file exists in
      ## the first file.
      if($3 in n){
        ## Add the value of the 5th field to the corresponding value
        ## of the n array.
        n[$3]+=$5
      }
    }
}
## The END{} block is executed after all files have been processed.
## This is useful since you may have more than one line whose 3rd
## field was specified in the first file so you don't want to print
## as you process the files.
END{
    ## For each element in the n array
    for (i in n){
    ## print the element itself and then its value
    print i,":",n[i];
    }
}

Vous pouvez l'enregistrer en tant que fichier, le rendre exécutable et l'exécuter comme suit:

$ chmod a+x foo.awk
$ ./foo.awk file1 file2
1 : 7
2 : 2
3 : 4

Ou, vous pouvez le condenser en un seul revêtement:

awk '
     (NR == FNR){n[$1] = 0; next}
     {if($3 in n){n[$3]+=$5}}
     END{for (i in n){print i,":",n[i]} }' file1 file2

9
awk '
  NR == FNR {n[$3] += $5; next}
  {print $1 ": " n[$1]}' file2 file1

Il fait un travail supplémentaire en additionnant les champs non correspondants.
Emmanuel

@Emmanuel, c'est toujours une instruction awk par ligne de fichier2, ce qui la rend plus courte et plus rapide que celle de terdon
Stéphane Chazelas

solution brillante!
Ronald Pauffert
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.