Blog ENI : Toute la veille numérique !
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici
💥 Les 22 & 23 novembre : Accès 100% GRATUIT
à la Bibliothèque Numérique ENI. Je m'inscris !
  1. Livres et vidéos
  2. Programmation shell sous Unix/Linux
  3. Le langage de programmation awk
Extrait - Programmation shell sous Unix/Linux ksh, bash, norme POSIX (avec exercices corrigés) (7e édition)
Extraits du livre
Programmation shell sous Unix/Linux ksh, bash, norme POSIX (avec exercices corrigés) (7e édition)
2 avis
Revenir à la page d'achat du livre

Le langage de programmation awk

Présentation

Le langage de programmation awk est un outil adapté au traitement de fichiers textes. Il permet d’effectuer des actions sur des enregistrements de données éventuellement structurés en champs. Le nom "awk" a pour origine les initiales du nom de chacun de ses auteurs : Aho, Weinberger et Kernighan. Ce chapitre présente les principales fonctionnalités des versions récentes du langage awk, appelées nawk (new awk) sur certaines plates-formes Unix. Sous Linux, la commande awk est un lien symbolique vers l’interpréteur gawk (GNU awk).

1. Syntaxe

awk [-F] '{action-awk}' [ fic1 ... ficn ] 
awk [-F] -f script-awk [ fic1 ... ficn ] 

La commande awk prend en argument la liste des fichiers à traiter. En l’absence de noms de fichiers sur la ligne de commande, awk travaille sur les données arrivant sur son entrée standard. Cette commande peut donc être placée derrière un tube de communication.

2. Version de gawk

La version de gawk s’obtient en utilisant l’option --version.

Exemple

$ gawk --version 
GNU Awk 4.1.3, API: 1.1 

3. Variables spéciales

a. Variables prédéfinies dès le lancement de awk

Le tableau suivant présente les principales variables internes du langage awk présentes en mémoire dès le lancement de la commande. La valeur de ces variables peut éventuellement être modifiée en fonction de la structure des données à traiter.

Nom de la variable

Valeur par défaut

Rôle de la variable

RS

Newline (\n)

Record Separator : caractère séparateur d’enregistrement (lignes).

FS

Suite d’espaces et/ou tabulations

Field Separator : caractères séparateurs de champ.

OFS

Espace

Output Field Separator : séparateur de champ utilisé...

Opérateurs

Le tableau suivant regroupe les opérateurs disponibles dans le langage.

Opérateur

Arité

Signification

Opérateurs arithmétiques

+

Binaire

Addition

-

Binaire

Soustraction

*

Binaire

Multiplication

/

Binaire

Division

%

Binaire

Modulo

ˆ

Binaire

Exponentiation

++

Unaire

Incrémentation d’une variable d’une unité

--

Unaire

Décrémentation d’une variable d’une unité

+=

Binaire

x+=y est équivalent à x=x+y

-=

Binaire

x-=y est équivalent à x=x-y

*=

Binaire

x*=y est équivalent à x=x*y

/=

Binaire

x/=y est équivalent à x=x/y

%=

Binaire

x%=y est équivalent à x=x%y

ˆ=

Binaire

xˆ=y est équivalent à x=xˆy

Opérateurs de tests

<

Binaire

Inférieur

>

Binaire

Supérieur

<=

Binaire

Inférieur ou égal

>=

Binaire

Supérieur ou égal

==

Binaire

Test d’égalité

!=

Binaire

Test d’inégalité

~

Binaire

Correspondance avec une expression régulière

!~

Binaire

Non correspondance avec une expression régulière

Opérateurs logiques

!

Binaire

Négation

&&

Binaire

Et logique

||

Binaire

Ou logique

Divers

=

Binaire

Affectation

e1 ? e2 : e3

Ternaire

L’expression globale vaut e2 si e1 est vrai, e3 dans le cas contraire

e1 e2 (opérateur espace)

Binaire

Concaténation de e1 et e2

Exemple de concaténation

Concaténation (opérateur espace) de la variable nom et de la variable prenom dans la variable nomPrenom :

$ awk 'BEGIN { nom="Durand" ; prenom="Michel" ; nomPrenom=nom prenom ;
print nomPrenom}' 
DurandMichel 

Même chose en concaténant le caractère espace entre le nom et le prénom :

$ awk 'BEGIN { nom="Durand" ; prenom="Michel"...

La fonction printf

awk propose la fonction intégrée printf similaire à celle du langage C. Elle permet de formater les affichages.

printf ("chaine",expr1,expr2, ..., exprn) 

chaine représente la chaîne qui sera affichée à l’écran. Elle peut contenir des formats qui seront substitués par la valeur des expressions citées à sa suite. Il doit y avoir autant de formats que d’expressions.

Exemples de formats couramment utilisés

%20s

Affichage d’une chaîne (string) sur 20 positions (cadrage à droite par défaut).

%-20s

Affichage d’une chaîne (string) sur 20 positions avec cadrage à gauche.

%3d

Affichage d’un entier (décimal) sur 3 positions (cadrage à droite).

%03d

Affichage d’un entier (décimal) sur 3 positions (cadrage à droite) complété par des 0 à gauche.

%-3d

Affichage d’un entier (décimal) sur 3 positions (cadrage à gauche).

%+3d

Affichage d’un entier (décimal) sur 3 positions (cadrage à droite) avec affichage systématique du signe (un nombre négatif est toujours affiché avec son signe).

%10.2f

Affichage d’un nombre flottant sur 10 positions dont 2 décimales.

%+010.2f

Affichage d’un nombre flottant sur 10 positions dont 2 décimales, cadrage à droite, affichage systématique du signe, complétion par des zéros à gauche.

Des exemples d’utilisation de la fonction printf sont donnés dans la suite de ce chapitre.

Redirections

Il est possible de rediriger les sorties du script vers un fichier ou vers une commande du système d’exploitation.

Syntaxe

instruction > "fichier" 

Au premier appel, ouverture en mode "écrasement", puis écriture. Les écritures ultérieures se font à la suite de la ligne précédente. L’expression "fichier" vaudra "/dev/stderr" pour écrire sur la sortie d’erreur standard.

instruction >> "fichier" 

Au premier appel, ouverture en mode "ajout", puis écriture. Les écritures ultérieures se font à la suite de la ligne précédente. L’expression "fichier" vaudra "/dev/stderr" pour écrire sur la sortie d’erreur standard.

print[f] "..." | "commande" 

Le résultat de l’instruction print est transmise sur l’entrée standard de la commande par l’intermédiaire d’un tube.

Premier exemple

Ouverture en mode écrasement :

$ nl redirect1.awk  
1 BEGIN { 
2     nomfic = "/tmp/fic.txt" 
3     print "Ligne 1" > nomfic 
4     print "Ligne 2" > nomfic 
5     print "Ligne 3" > nomfic 
6     close(nomfic) 
7 } 

Exécution :

$ date > /tmp/fic.txt # création d'un fichier non vide  
$ cat /tmp/fic.txt 
mer. jan 26 14:14:32 CET 2022 
$ awk -f redirect1.awk # Exécution du script awk 
$ cat /tmp/fic.txt # Le contenu précédent a été écrasé 
Ligne 1 
Ligne 2 
Ligne 3 
$ 

Deuxième exemple

Ouverture en mode ajout :

$ nl redirect2.awk 
1 BEGIN { ...

Lecture de la ligne suivante : next

L’instruction next interrompt le traitement de la ligne courante et déclenche la lecture de la ligne suivante, sur laquelle le traitement intégral sera appliqué.

Exemple

Le script region1.awk réaffiche le fichier tel3.txt en ajoutant un champ avant le téléphone contenant la valeur RP pour les clients localisés en région parisienne et REGION pour les clients localisés en province.

$ nl region1.awk  
    1  BEGIN {  
    2    FS="|"  
    3  }  
 
    4  $3 ~ /^(7[578]|9[1-5])/ {  
    5    printf ("%s|%s|%s|%s|RP|%s\n",$1,$2,$3,$4,$5)  
    6    # Saut à l'enregistrement suivant  
    7    next  
    8  }  
 
    9  {  
    10    printf ("%s|%s|%s|%s|REGION|%s\n",$1,$2,$3,$4,$5)  
    11  } 

Exécution :

$ awk -f region1.awk tel3.txt 
Joyeux Giselle|12. rue de la Source|89290|Vaux|REGION|03.45.26.28.47 
Dehaut Olivier|3 rue de Pussenval|75020|Paris|RP|01.78.25.96.78 
Karama Josette|256 rue de la tempete|56100|Lorient|REGION|02.85.26.45.58 
Zanouri Joel|45/48 boulevard du Gard|56100|lorient|REGION|02/85/56/45/58 
Gron Pierre|89-90 rue du chateau|38350|La Mure|REGION|04.78.21.23.69 
Grival Zoe|3, rue du chateau|38350|La Mure|REGION|04.78.21.78.69 
$ 

Lignes 4 à 8 : la première section intermédiaire traite les codes postaux d’Ile de France. Dès que le traitement est terminé, l’instruction next redémarre...

Structures de contrôle

awk propose des structures de contrôle que l’on retrouve classiquement dans les langages de programmation. La syntaxe est héritée du langage C.

1. if

La partie else est facultative.

Syntaxe

if (condition) { 
    instruction 
    ... 
}  
else { 
    instruction 
    ... 
} 

Lorsqu’une seule instruction est présente, les accolades sont facultatives :

if (condition)  
    instruction 
else  
    instruction 

2. switch

gawk

La structure de contrôle switch (l’équivalent en shell est la structure case) permet également de faire des tests.

La structure de contrôle switch est disponible en standard à partir de la version 4 de gawk (dans les versions supérieures à 3.1.3 et inférieures à 4, switch est disponible si gawk est compilé avec l’option --enable-switch).

Syntaxe

switch (expression) {  
  case valeur|expression-reguliere :   
      instruction  
      instruction  
        ...  
      break   
  case valeur|expression-reguliere :   
      instruction  
      instruction  
        ...  
      break   
  [ default :   
      instruction  
      instruction  
      break ]  
} 

Exemple

Le programme switch.gawk teste en ligne 6 le code postal ($3) présent dans le fichier tel3.txt. La valeur de la variable $3 est comparée aux différents cas (lignes 7, 10 et 13). Dès que l’un des cas est vrai, le switch se termine. Chaque...

Terminer un script

L’instruction exit permet à tout moment de terminer un script en retournant un statut au système d’exploitation.

Exemple

{ 
    if ( NF < 3) exit 1 ; # Fin du script avec statut faux 
    . . . 
    . . .  
} 
 
END{ 
    exit 0 # Fin du script avec statut vrai 
} 

Tableaux

Les éléments d’un tableau peuvent être indicés par un nombre ou par une chaîne de caractères. Cet indice est toujours vu comme une chaîne de caractères car dans le langage awk, tous les tableaux sont associatifs. Nous distinguerons néanmoins les deux cas de figure.

1. Tableaux indicés par un nombre

L’indice de départ est au choix du développeur.

Exemple

Ce script initialise un élément de tableau à chaque nouvel enregistrement traité. Le fichier traité est tel3.txt. Chaque élément représente le nom d’un client. Ce tableau est indicé à partir de 1 :

$ nl tab.awk 
    1 # Section BEGIN 
    2 BEGIN { 
    3 FS="|"  
    4 }  
  
    5 # Tableau stockant les noms des clients 
    6 { 
    7 client[NR]=$1 
    8 } 
 
    9 # Section END 
    10 END { 
    11    # Affichage du tableau 
    12    for (indice=1 ; indice <= NR ; indice++) { 
    13      printf("Client no %4d => %-20s\n",indice, client[indice]); 
    14    } 
    15  } 
$ 

Résultat de l’exécution :

$ awk -f tab.awk tel3.txt 
Client no    1 => Joyeux Giselle 
Client no    2 => Dehaut Olivier 
Client no    3 => Karama Josette  
Client no    4 => Zanouri Joel 
Client no    5 => Gron Pierre ...

Tableaux multidimensionnels

1. Simulation de tableaux multidimensionnels

Exception faite de gawk à partir de la version 4, les vrais tableaux multidimensionnels n’existent pas. Néanmoins, un mécanisme permet de simuler le fonctionnement d’un tableau multidimensionnel.

Exemple

$ nl tab2d.awk  
    1  BEGIN {  
    2    # Clé unique  
    3    tab[0,"nom"] = "Petit"  
    4    tab[0,"cp"] = "75001"  
    5    tab[1,"nom"] = "Dupont"  
    6    tab[1,"cp"] = "89000"  
 
    7 
    8    for (i=0; i<=1; i++) {  
    9      print "Indice " i " : "  
   10      print "Nom : " tab[i,"nom"]  
   11      print "CP  : " tab[i,"cp"]  
   12      print "------------"   
   13    }  
   14        
 
   15    for (cle in tab) {  
   16      print "Clé : --" cle "-- Valeur => " tab[cle]  
   17    }  
   18  } 

En réalité, la clé [0,"nom"] est stockée en interne sous forme d’une seule clé "0\034nom". La valeur \034 est le caractère séparateur (en mémoire) et est contenue dans la variable SUBSEP ; cette valeur est matérialisée par une virgule entre les crochets.

En ligne 16, la boucle affiche la valeur de la clé. En regardant le résultat ci-dessous, nous...

Les arguments de la ligne de commande

Les variables ARGV et ARGC

awk fournit un mécanisme qui permet de passer des arguments à un script au moment de son appel. Les variables ARGC et ARGV sont initialisées par awk et permettent de traiter les valeurs passées sur la ligne de commande. ARGV est un tableau qui contient les arguments reçus, hors options awk de la ligne de commande (ci-dessous -f arg.awk). ARGV[0] représente le nom de la commande (donc awk). Les valeurs contenues dans les postes suivants du tableau ARGV seront considérés comme les noms de fichier à traiter par les sections intermédiaires. ARGC contient le nombre d’arguments reçus. ARGV et ARGC sont disponibles dans toutes les sections du script.

Exemple

$ nl arg.awk 
     1  #! /bin/awk  
 
     2  BEGIN{ 
     3    print "ARGC = " , ARGC  
     4    for (i=0;i<ARGC;i++) { 
     5        printf("ARGV[%d] = %s\n",i, ARGV[i]) 
     6    } 
     7  } 
$ 
$ awk -f arg.awk agenda.txt tel3.txt 
ARGC = 3 
ARGV[0] = awk 
ARGV[1] = agenda.txt 
ARGV[2] = tel3.txt 

Transmettre des variables au script AWK à partir de la ligne de commande (versions actuelles de awk)

Sur les versions actuelles de awk (nawk,gawk), l’option -v est prévue pour initialiser des variables à partir de la ligne de commande. Ces variables seront disponibles dans toutes les sections du script (BEGIN, END et sections intermédiaires).

Syntaxe

$ awk -f script.awk -v var1=valeur1 [ -v var2=valeur2 ... ] 
[fichier_a_traiter] 

Exemple

Le script agenda1.awk permet de rechercher des informations dans le fichier agenda.txt. L’utilisateur...

Fonctions intégrées

Le langage awk dispose de fonctions intégrées.

1. Fonctions travaillant sur les chaînes

Fonction

Rôle

gsub(er,remp,[ch])

Remplace dans la chaîne "ch" chaque occurrence correspondant à l’expression régulière "er" par la chaîne "remp". Retourne le nombre de substitutions. Par défaut, "ch" vaut $0.

index(ch1,ch2)

Retourne la position de la sous-chaîne "ch2" dans la chaîne "ch1".

length(ch)

Retourne la longueur de la chaîne "ch".

match(ch,er)

Retourne la position dans la chaîne "ch" de la première occurrence de l’expression régulière "er".

split(ch,tab,sep)

Initialise le tableau "tab" avec les champs de la chaîne "ch". "sep" représente le séparateur de champ. Retourne le nombre de champs.

sprintf(fmt,e1,...,en)

Identique à printf, mais retourne la chaîne formatée.

sub(er,remp,[ch])

Remplace dans la chaîne "ch" la première occurrence correspondant à l’expression régulière "er" par la chaîne "remp". Retourne le nombre de substitutions. Par défaut, "ch" vaut $0.

substr(ch,pos,lg)

Retourne la sous-chaîne de "ch" commençant à la position "pos" et de longueur "lg".

tolower(ch)

Retourne la valeur de la chaîne "ch" convertie en minuscules.

toupper(ch)

Retourne la valeur de la chaîne "ch" convertie en majuscules.

2. Fonctions mathématiques

Fonction

Rôle

cos(x)

Retourne le cosinus de x

exp(x)

Retourne e à la puissance x

int(x)

Retourne la valeur entière de x

log(x)

Retourne le logarithme naturel de x

sin(x)

Retourne le sinus de x

sqrt(x)

Retourne la racine carrée...

Fonctions utilisateur

Syntaxe

Une fonction peut recevoir de 0 à n arguments et retourner une valeur explicite. Les fonctions peuvent être définies au-dessus ou au-dessous de leur appel.

Définition d’une fonction :

function nom_fonction (param1, param2 ... paramn) { 
 
return valeur 
} 

Les paramètres (param1, param2 ... paramn) sont des variables locales. Toute autre variable définie dans la fonction est globale.

Appel d’une fonction :

valeur_retournee=nom_fonction(val1, val2, ..., valn) 

Il ne doit pas y avoir d’espace entre le nom de la fonction et la parenthèse ouvrante. 

Exemple

Le script region2.awk réaffiche le fichier tel3.txt en ajoutant un champ avant le téléphone ; ajout de la valeur " RP " pour les clients localisés en région parisienne et " REGION " pour les clients localisés en province.

La fonction getRegion() reçoit en argument le code postal et retourne la chaine représentant la région.

$ nl region2.awk 
    1  # fonction qui retourne la valeur de la région 
    2  function getRegion (cp) { 
    3    # Region parisienne 
    4    if ( cp ~ /^7[578]|9[1-5])/ ) { 
    5      return "RP" 
    6    } 
    7    return "REGION" 
    8  } 
 
    9  # Section BEGIN 
    10  BEGIN { 
    11    FS="|" 
    12  } 
 
    13  # Section...

Inclusions de fichiers

gawk >= 4

Le langage gawk offre, à partir de sa version 4, la possibilité d’inclure dans le code source le contenu d’autres fichiers, grâce à la directive @include. La variable d’environnement AWKPATH pourra être initialisée avec le nom des répertoires où gawk doit rechercher les fichiers à inclure (même principe que la variable PATH Unix). Si AWKPATH est initialisée, elle doit également contenir l’emplacement du script principal.

Exemple d’inclusion

Le fichier à inclure :

$ nl affiche.inc.gawk  
    1  function affiche(message) { print message  } 

Le programme principal :

$ nl include.gawk  
       
    1  @include "affiche.inc.gawk"  
       
    2  BEGIN {   affiche("Hello")  }  
 
$ gawk -f include.gawk   
Hello
$ 

Exemple d’utilisation de AWKPATH

Le programme principal :

/home/christie/awk/AWKPATH/include.gawk 

inclut :

/home/christie/awk/AWKPATH/includes/affiche.inc.gawk 

Définition de la variable AWKPATH qui doit contenir l’emplacement du programme principal et l’emplacement des fichiers à inclure :

$ AWKPATH=/home/christie/awk/AWKPATH:/home/christie/awk/AWKPATH/includes 
$ export AWKPATH 
$ gawk -f include.gawk 
Hello 
$ 

La variable et son exportation peuvent être placés dans le fichier .bash_profile / .profile pour un paramétrage permanent.

Exercices

Les fichiers fournis pour les exercices sont disponibles dans le répertoire dédié au chapitre sous l’arborescence Exercices/fichiers.

1. awk en ligne de commande

a. Exercice 1 : awk et autres filtres

Commandes filtres utiles : awk, grep (cf. chapitre Les commandes filtres), sed (cf. chapitre La commande sed). Autre commande utile : file.

Faire afficher les noms des fichiers texte du répertoire /etc.

Exemple de résultat

adjtime 
aliases 
asound.conf 
auto.master 
auto.misc 
. . . 

b. Exercice 2 : critères de sélection

1.

Dans votre répertoire courant, afficher les caractéristiques des fichiers dont le nom commence par un point (uniquement ceux-là).

Exemple de résultat

drwxr-xr-x. 24 christie christie  4096  3 févr. 12:26 . 
drwxr-xr-x. 11 root     root      4096 27 janv. 14:06 .. 
-rw-------.  1 christie ociensa  14752 22 janv. 12:40 .bash_history 

2.

Dans votre répertoire courant, afficher les noms de fichiers commençant par un point, sauf "." et "..".

Exemple de résultat

.bash_history 
.bash_logout 
.bash_profile 
.bashrc 

c. Exercice 3 : critères de sélection, affichage de champs, sections BEGIN et END

À partir du fichier php.ini fourni :

1.

Faire afficher les lignes qui ne commencent pas par ";" et qui se terminent par On ou Off.

Exemple de résultat

engine = On 
short_open_tag = Off 
asp_tags = Off 
zlib.output_compression = Off 
implicit_flush = Off 

2.

Améliorer l’affichage.

Exemple de résultat

engine                                   On  
short_open_tag                           Off  
asp_tags  ...