Les utilitaires awk, nawk et gawk - Tutoriel


1- Introduction

Les utilitaires awk, nawk et gawk (GNU Awk) sont des parseurs de fichiers textes très simples à utiliser et permettent de manipuler efficacement des fichiers textes de données délimitées par un caractère. Avec une syntaxe très facile à appréhender, les opérations pour filtrer des lignes, filtrer des colonnes, enrichir le contenu, convertir des formats, calculer des agrégats (moyennes, sommes par exemple) etc... deviennent un jeu d'enfants avec ces utilitaires. awk, gawk et nawk ne diffèrent que pour quelques fonctionnalités très avancées qui ne sont pas abordées ici.

awk est l'utilitaire qu'il faut utiliser sans hésiter pour parser très efficacement et en quelques secondes des fichiers de logs complexes par exemple.

Voici un tutoriel pour prendre en main l'utilitaire nawk à travers l'exemple, et contrairement aux idées reçues il est également disponible sur les plateformes Windows :

Pour l'histoire, awk est né dans les années 70 pour les OS Unix et est un acronyme avec les noms des auteurs de cet utilitaire : Aho, Weinberger et Kernighan.

2- Prendre en main awk

2-1- Le fichier csv du tutoriel (Hello World)

Ce tutoriel utilise le fichier file.txt ci-dessous, fichier dans lequel les colonnes sont séparées par des tabulations :

shell> cat file.txt
Nom             Genre           Age
---------------------------------------
CAMILLE         M               7
CHLOE           F               12
CLARA           F               11
CLEMENT         M               7
EMMA            F               6
THEO            M               8

2-2- Extraire des colonnes avec awk

Extraire des données d'un fichier, par exemple les 2 premières colonnes :

shell> nawk '{ print $1, $2 }' file.txt
Nom Genre
--------------------------------------- 
CAMILLE M
CHLOE F
CLARA F
CLEMENT M
EMMA F
THEO M

Noter la structure d'un programme awk entre quotes et accolades (brackets)

Dans le format de la sortie, les tabulations sont remplacées par un espace qui est le séparateur de sortie par défaut.

Un point important à considérer avec awk : son comportement particulier avec les espaces et les tabulations. Par défaut, les espaces et tabulations contigüs sont considérés comme un séparateur unique. Il s'agit de la seule exception.

2-3- Appliquer des filtres avec des expressions régulières dans awk

Précédemment, des colonnes ont été filtrées, mais awk est aussi principalement utilisé pour filtrer des lignes grâce aux syntaxes des expressions régulières.

Retrouver les lignes qui contiennent CAMILLE :

shell> nawk '/CAMILLE/ { print $1, $3, $2 }' file.txt
CAMILLE 7 M

L'ordre des colonnes a été modifié pour l'exemple.

Un autre filtre plus complexe, rechercher les lignes qui commencent par C et qui contiennent la lettre A ou la lettre O :

shell> nawk '/^C.*[AO]/ { print $1, $3, $2 }' file.txt
CAMILLE 7 M
CHLOE 12 F
CLARA 11 F

Pour plus d'informations sur les expressions régulières : Regular-Expressions.info

awk est également très utile et puissant pour gérer des filtres sur des paragraphes. Pour récupérer les lignes de CL à E :

shell> nawk '/^CL/,/^E/ { print $0 }' file.txt
CLARA F 11
CLEMENT M 7
EMMA F 6

2-4- Variables internes avec awk

awk fournit des variables utiles qui peuvent être utilisées, affichées, calculées ou assignées :

shell> nawk '{ print NR, NF, $0 }' file.txt
1 3 Nom         Genre           Age
2 1 ---------------------------------------
3 3 CAMILLE             M               7
4 3 CHLOE               F               12
5 3 CLARA               F               11
6 3 CLEMENT             M               7
7 3 EMMA                F               6
8 3 THEO                M               8
shell> nawk '/CAMILLE/ { OFS="," ; print $2,$1 }' file.txt
M,CAMILLE

À noter le caractère ";" pour séparer les instructions dans la même ligne et la façon dont on assigne une valeur à une variable (OFS=",").

La variable ENVIRON est un tableau qui contient les variables d'environnement de l'utilisateur. Ici, la variable EDITOR de l'utilisateur est affichée avec awk :

shell> nawk '/EMMA/ { OFS="," ; print $2,$1, ENVIRON["EDITOR"]}' file.txt
F,EMMA,vi

À noter la manière d'adresser le contenu d'un tableau : array["tag"]

2-5- Scripts awk

awk a été utilisé précédemment en mode lignes de commande. Lorsque le programme awk devient complexe, ce dernier peut être stocké dans un fichier prog.awk

shell> cat prog.awk
/^CL/,/^E/ { 
     print NR, $0 
}

puis interprété grâce à l'option -f

shell> nawk -f prog.awk file.txt
5 CLARA F 11
6 CLEMENT M 7
7 EMMA F 6

2-6- Pré et Post opérations

awk offre des sections pré-traitement (BEGIN) et post-traitement (END) lors de l'analyse d'un fichier. La structure du script awk est :

BEGIN {
        action
}

/filter/,/filter/ { action }

{ action}

END {
        action
}

Les blocs BEGIN et END ne sont pas obligatoires. Il peut y avoir un bloc BEGIN sans bloc END, un bloc END sans bloc BEGIN, ou aucun de ces 2 blocs.

Des scripts bien plus complexes peuvent alors être écrits. Par exemple, extraire 2 colonnes en remplaçant les tabulations par des ";" et afficher le nombre de lignes à la fin :

shell> cat prog.awk
BEGIN { 
        FS=" "
        OFS=";"
}
{ 
        print $1, $3 
}
END { 
        printf "\nThe file has %d lines\n", NR 
}

shell> nawk -f prog.awk file.txt
Nom;Age
---------------------------------------;
CAMILLE;7
CHLOE;12
CLARA;11
CLEMENT;7
EMMA;6
THEO;8

The file has 8 lines 

3- Fonctions

3-1- Fonctions internes

Le parseur awk offre beaucoup de fonctions internes très utiles pour traiter les données. Consulter les manuels de l'utilitaire awk pour la liste complète des fonctions internes, en voici une liste partielle :

3-1-1- toupper, tolower

Convertir du texte en majuscules ou en minuscules avec les fonctions toupper et tolower

shell> nawk '/THEO/ { print $1, tolower($1) }' file.txt
THEO theo

3-1-2- int

Convertir une valeur en entier avec la fonction int :

shell> nawk '/CHLOE/ { print $3, int($3/5}' file.txt
12 2

3-1-3- printf

La fonction printf avec awk fonctionne comme la fonction printf en C afin de formatter la sortie :

shell> nawk 'NR > 2 { printf "%10s %02d %-10s\n", $1,$3, $1}' file.txt
   CAMILLE 07 CAMILLE   
     CHLOE 12 CHLOE     
     CLARA 11 CLARA     
   CLEMENT 07 CLEMENT   
      EMMA 06 EMMA      
      THEO 08 THEO 

3-1-4- length

Afficher la taille d'une chaîne de caractères avec la fonction length :

shell> nawk '/CLEM/ { print $1, length($1) }' file.txt
CLEMENT 7

3-1-5- match

Retourne la position d'une chaîne de caractères remplissant les critères d'une expression régulière avec la fonction match :

shell> nawk 'NR >2 { print $1, match($1,"A")}' file.txt
CAMILLE 2
CHLOE 0
CLARA 3
CLEMENT 0
EMMA 4
THEO 0

3-1-5- gsub

Remplacer des chaînes de caractères avec la fonction gsub :

Shell> nawk 'NR >2 { gsub("A","_",$1) ; print $1 }' file.txt
C_MILLE
CHLOE
CL_R_
CLEMENT
EMM_
THEO

3-1-6- substr

Extraire une portion de texte avec la fonction substr :

shell> nawk '{ print $1, substr($1,2,3) }' file.txt
Nom om
--------------------------------------- ---
CAMILLE AMI
CHLOE HLO
CLARA LAR
CLEMENT LEM
EMMA MMA
THEO HEO

3-2- Fonctions utilisateur

La possibilité de créér des fonctions utilisateur est une des fonctionnalités les plus importantes de l'utilitaire awk. Les fonctions sont définies avec le mot clé function.

shell> cat prog.awk
function gentag(nom,age) {
        tmp=tolower(substr(nom,1,3))
        return tmp "_" age
}

BEGIN { 
        FS=" "
        OFS=";"
}

{ 
        print $1, $3, gentag($1,$3)
}

END { 
print NR , "lines"
}

shell> nawk -f prog.awk file.txt
Nom;Age;nom_Age
---------------------------------------;;---_
CAMILLE;7;cam_7
CHLOE;12;chl_12
CLARA;11;cla_11
CLEMENT;7;cle_7
EMMA;6;emm_6
THEO;8;the_8
8;lines

4- Programmation

Le parseur awk offre toutes les structures de programmation : conditions, boucles, itérations.

4-1- Condition

Les enfants sont ils en primaire ou au collège avec if() {} else {} ?

shell> cat prog.awk
BEGIN {
        OFS=","
}
NR <=2 { next }
{
        if ( $3 < 11 ) {
                ecole="primaire"
        } else {
                ecole="college"
        }

        print $1, ecole
}

shell> nawk -f prog.awk file.txt
CAMILLE,primaire
CHLOE,college
CLARA,college
CLEMENT,primaire
EMMA,primaire
THEO,primaire

Remarquer la façon dont l'entête est écartée : NR <=2 { next }

4-2- Boucles

Remplacer l'âge de l'enfant par un nombre de points avec while() {}.

shell> cat prog.awk
NR <=2 { next }
{
        min=1
        printf "%-10s", $1
        while  ( min <= $3 ) {
                printf "."
                min++
        }
        printf "\n"
}

shell> nawk -f prog.awk file.txt
CAMILLE   .......
CHLOE     ............
CLARA     ...........
CLEMENT   .......
EMMA      ......
THEO      ........

4-3- Itérations

Remplacer l'âge de l'enfant par un nombre de points avec for (i= ; i< ; i++ ) { }.

shell> cat prog.awk
NR <=2 { next }
{
        printf "%-10s", $1
        for ( min=1 ; min <= $3; min++ ) {
                printf "."
        }
        printf "\n"
}

shell> nawk -f prog.awk file.txt
CAMILLE   .......
CHLOE     ............
CLARA     ...........
CLEMENT   .......
EMMA      ......
THEO      ........

5- Tableaux (Arrays)

Pour terminer cette brève présentation : les tableaux avec awk, particulièrement pratiques pour calculer des agrégats. La structure d'un tableau avec awk est très simple :

tab[indice] = value

Calculer la moyenne d'âge des enfants par sexe :

shell> cat prog.awk
{ 
        if ( NR <= 2 ) { next } # skip first 2 lines
        tab_age[$2]+=$3
        tab_cpt[$2]++
}
END { 
        for ( genre in tab_age ) { 
        print genre, " : ", "Moy :", int(tab_age[genre]/tab_cpt[genre]), "ans", "nb :", tab_cpt[genre] 
        }
}

nawk -f prog.awk file.txt
F : Moy : 9 ans nb : 3
M : Moy : 7 ans nb : 3

Remarquer comment les 2 tableaux sont remplis et traités à la fin.


Annexe

Historique

Version Date Commentaires
1.0 11/2011 Version initiale

Liens

UnxUtils
Cygwin
MingW - Minimalist Gui For Windows
Regular-Expressions.info