Introduction
Les utilitaires awk
, nawk
et gawk
(GNU Awk) sont des parseurs de fichiers textes très simples à utiliser. Ils 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 aggré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 :
- UnxUtils pour Windows (gawk) : http://sourceforge.net/projects/unxutils/
- Cygwin (gawk) : http://www.cygwin.com/
- MingW - Minimalist Gui for Windows (awk) : http://www.mingw.org/
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.
Prendre en main awk
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 :
file.txt
Nom Genre Age
---------------------------------------
CAMILLE M 7
CHLOE F 12
CLARA F 11
CLEMENT M 7
EMMA F 6
THEO M 8
Extraire des colonnes avec awk
Extraire des données d’un fichier, par exemple les 2 premières colonnes :
%> 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)
$1
correspond à la première colonne,$2
la seconde,$3
la troisième…$0
correspond à la ligne entière.
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.
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 :
%> 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 :
%> 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 :
%> nawk '/^CL/,/^E/ { print $0 }' file.txt
CLARA F 11 CLEMENT M 7 EMMA F 6
Variables internes avec awk
awk
fournit des variables utiles qui peuvent être utilisées, affichées, calculées ou assignées.
NR
: nombre d’enregistrements lus (numéro de ligne).NF
: nombre de champs (nombre de colonnes).
%> 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
FS
: Séparateur de champ (par défaut : espace/tabulation).OFS
: Séparateur de champ en sortie (par défaut : espace).
%> 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
:
%> 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"]
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
prog.awk
/^CL/,/^E/ {
print NR, $0
}
puis interprété grâce à l’option -f
%> nawk -f prog.awk file.txt
5 CLARA F 11 6 CLEMENT M 7 7 EMMA F 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 d’un 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 :
prog.awk
BEGIN {
FS=" "
OFS=";"
}
{
print $1, $3
}
END {
printf "\nThe file has %d lines\n", NR
}
%> 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
Fonctions
Fonctions internes
Le parseur awk
offre beaucoup de fonctions internes 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 :
toupper, tolower
Convertir du texte en majuscules ou en minuscules avec les fonctions toupper
et tolower
%> nawk '/THEO/ { print $1, tolower($1) }' file.txt
THEO theo
int
Convertir une valeur en entier avec la fonction int
:
%> nawk '/CHLOE/ { print $3, int($3/5}' file.txt
12 2
printf
La fonction printf
avec awk
fonctionne comme la fonction printf
en C afin de formater la sortie :
%> 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
length
Afficher la taille d’une chaîne de caractères avec la fonction length
:
%> nawk '/CLEM/ { print $1, length($1) }' file.txt
CLEMENT 7
match
La fonction match
retourne la position d’une chaîne de caractères remplissant les critères d’une expression régulière :
%> nawk 'NR >2 { print $1, match($1,"A")}' file.txt
CAMILLE 2 CHLOE 0 CLARA 3 CLEMENT 0 EMMA 4 THEO 0
gsub
Remplacer des chaînes de caractères avec la fonction gsub
:
%> nawk 'NR >2 { gsub("A","_",$1) ; print $1 }' file.txt
C_MILLE CHLOE CL_R_ CLEMENT EMM_ THEO
substr
Extraire une portion de texte avec la fonction substr
:
%> nawk '{ print $1, substr($1,2,3) }' file.txt
Nom om --------------------------------------- --- CAMILLE AMI CHLOE HLO CLARA LAR CLEMENT LEM EMMA MMA THEO HEO
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
.
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"
}
%> 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
Programmation
Le parseur awk
offre toutes les structures de programmation : conditions, boucles, itérations.
Condition
Les enfants sont ils en primaire ou au collège avec if() {} else {}
?
prog.awk
BEGIN {
OFS=","
}
NR <=2 { next }
{
if ( $3 < 11 ) {
ecole="primaire"
} else {
ecole="college"
}
print $1, ecole
}
%> 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 }
Boucles
Remplacer l’âge de l’enfant par un nombre de points avec while() {}
.
prog.awk
NR <=2 { next }
{
min=1
printf "%-10s", $1
while ( min <= $3 ) {
printf "."
min++
}
printf "\n"
}
%> nawk -f prog.awk file.txt
CAMILLE ....... CHLOE ............ CLARA ........... CLEMENT ....... EMMA ...... THEO ........
Itérations
Remplacer l’âge de l’enfant par un nombre de points avec for (i= ; i< ; i++ ) { }
.
prog.awk
NR <=2 { next }
{
printf "%-10s", $1
for ( min=1 ; min <= $3; min++ ) {
printf "."
}
printf "\n"
}
%> nawk -f prog.awk file.txt
CAMILLE ....... CHLOE ............ CLARA ........... CLEMENT ....... EMMA ...... THEO ........
Tableaux (Arrays)
Pour terminer cette brève présentation : les tableaux avec awk
, particulièrement pratiques pour calculer des aggrégats. La structure d’un tableau avec awk
est très simple :
tab[indice] = value
Calculer la moyenne d’âge des enfants par sexe :
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 du programme.