AWK

Note : j'utilise dans cette page les simplifications orthographiques RFF (Règles du Français Facile).


Le but de cette page est de montrer quelques fonctionalités du langage de programation AWK, un langage de traitement de fichiers de texte.

Organisation des programes AWK

Un programe awk se compose de trois sections dont certaines peuvent être omises :

BEGIN { /* section d'initiatisation */ } Règle { /* code à exécuter */ } END { /* section finale */ }

Exemple 1 - \$0, \$1, \$2

Considérons le fichier de donées en entrée data.txt :

abc ; def ; ghi jkl ; mno;pqr ; stu vwx ; yz

Voici un premier script AWK composé d'une seule ligne qui ne comporte pas de règle de reconaissance mais juste du code à exécuter. Cela signifie que ce code sera exécuté pour chaque ligne:

/* awk1.awk */ { print $2 }

L'exécution sera réalisée en utilisant le programme awk et en passant en paramètre le fichier de code awk (option -f) ainsi que le fichier de données :

awk -f awk1.awk data.txt ; ; stu ;

On pourra également utiliser la syntaxe cat data.txt | awk -f awk1.awk pour exécuter le script.

Le résultat de l'exécution est l'afichage du deuxième mot de chaque ligne car le séparateur par défaut est l'espace. Par exemple pour la première ligne du fichier data.txt, le deuxième mot est le point-virgule.

Si on utilise { print $0; } on affiche l'ensemble de la ligne.

Exemple 2 - Séparateur de champ FS

On peut modifier le séparateur de champs FS (Field Separator) qui sépare les mots sur une ligne. Dans notre exemple on va le fixer à ';' dans la section d'initialisation :

BEGIN { FS=";" } { print $2 }

Le résultat de l'exécution est alors :

def mno stu yz

Exemple 3 - Nombre de champs NF

AWK possède des variables prédéfinies comme NF (Number of Fields) le nombre de champs (ou de mots) sur une ligne et que l'on peut utiliser dans les scripts

BEGIN { FS=";" } { print NF, $2 }

Le résultat de l'exécution est alors :

3 def 3 mno 2 stu 2 yz

Exemple 4 - Nombre d'enregistrements NR

NR (Number of Records) est une variable prédéfinie qui correspond à la n-ième ligne du fichier de donées à traiter.

BEGIN { FS=";" } { print NR, NF, $2 }

Le résultat de l'exécution est alors :

1 3 def 2 3 mno 3 2 stu 4 2 yz

Exemple 5 - Utilisation des tableaux

Il est possible d'utiliser des tableaux (associatifs) afin de stocker des résultats intermédiaires. Voici un petit programe qui stocke le deuxième champs de chaque ligne dans un fichier.

BEGIN { FS=";"; nbr = 0 } { my_array[nbr++] = \$2; } END { print "there are ", nbr, "elements" for (i in my_array) { print i, my_array[i] } }

Le résultat de l'exécution est alors :

there are 4 elements 0 def 1 mno 2 stu 3 yz

Exemple 6 - Some

Dans l'exemple qui suit on traite un fichier de donées numériques : on stocke les valeurs dans un tableau et on en calcule la some.

Le fichier de donées en entrée est numeric_data.txt :

# Numeric data 12.5 13.2 8.7 9.78 15.76

Le script à exécuter est :

BEGIN { FS=";"; nbr = 0 } /^#/ { print "comment", \$0 } /^[0-9]+/{ my_array[++nbr] = \$1; } END { print "there are ", nbr, "elements" sum = 0; for (i in my_array) { print i, my_array[i] sum += my_array[i] } print "sum = ", sum }

Il est composé de deux règles :

Dnas la partie finale on réalise la some des valeurs. On notera la syntaxe particulière for (i in my_array)i se révèle être un itérateur sur les clés du tableau associatif.

Le résultat de l'exécution est :

there are 5 elements 1 12.5 2 13.2 3 8.7 4 9.78 5 15.76 sum = 59.94

Exemple 7 - Somme, moyenne, min, max

Enfin un dernier exemple (cf stats.awk) qui pour une série de valeurs calcule la some des valeurs, leur moyène, la variance, l'écart type, l'élément minimum et l'élément maximum.

# compute sum, average, var, std dev, min and max BEGIN { FS=";"; nbr = 0 } /^#/ { print "comment", \$0 } /^[+|-]?[1-9]+[.]?[0-9]*/{ my_array[++nbr] = \$1; } END { print "there are ", nbr, "elements" sum = 0; min = max = my_array[1] for (i in my_array) { value = my_array[i] print i, value sum += value if (value < min) min = value if (value > max) max = value } avg = sum / nbr var = 0 for (i in my_array) { var += (my_array[i] - avg) * (my_array[i] - avg) } std = sqrt(var / nbr) print "---------------" print nbr, ";", sum, ";", avg, ";", var, ";", std, ";", min, ";", max }

Sur l'exemple suivant :

# weights 60 56 61 68 51 53 69 54

On obtient :

comment # weights there are 8 elements 1 60 2 56 3 61 4 68 5 51 6 53 7 69 8 54 --------------- 8 ; 472 ; 59 ; 320 ; 6.32456 ; 51 ; 69

Soit :