awk est un langage de traitement de flux orienté enregistrements. Là où grep filtre des lignes entières et cut extrait des colonnes fixes, awk travaille sur la structure des données : il découpe chaque ligne en champs, applique des conditions par champ, accumule des valeurs dans des variables et reformate la sortie. Pas besoin d'un script Python pour calculer le total d'un CSV ou compter les codes d'erreur dans un log, awk fait ça en une ou deux lignes.
C'est un objectif direct LFCS ("Compare and Manipulate File Content") et RHCSA ("Process text streams using filters").
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Accéder aux champs automatiques
$1,$NF,NRetNF - Changer le séparateur avec
-Fpour parser:,,ou n'importe quel délimiteur - Filtrer des lignes avec des conditions numériques (
$3 >= 1000) et des regex ($1 ~ /pattern/) - Utiliser
BEGINetENDpour afficher des en-têtes et calculer des totaux - Construire un tableau associatif pour compter des occurrences par valeur
- Reformater proprement une sortie avec
printf
Dans quel contexte ?
Section intitulée « Dans quel contexte ? »awk intervient dès que vous avez besoin de raisonner sur la structure d'une ligne plutôt que sur son contenu texte brut :
- extraire le login et le shell de tous les comptes système depuis
/etc/passwd - calculer le chiffre d'affaires total depuis un export CSV
- compter les codes HTTP 4xx et 5xx par IP dans un access.log
- afficher uniquement les processus d'un utilisateur depuis la sortie de
ps - reformater une sortie de commande en tableau lisible avec des colonnes alignées
awk n'est pas un langage de script complet comme Python, mais pour les opérations de traitement de flux en ligne de commande, il est plus rapide à écrire, plus lisible qu'un pipeline complexe, et disponible partout.
Les deux jeux de données du guide
Section intitulée « Les deux jeux de données du guide »Toutes les sorties de ce guide proviennent des deux fichiers ci-dessous. Créez-les dans un répertoire de travail pour reproduire chaque commande et comparer votre résultat au résultat affiché. Le premier est un extrait de journal au format Combined Log produit par Apache et nginx ; le second est un export CSV de ventes avec une ligne d'en-tête, exactement le genre de fichier qu'on récupère d'un tableur.
cat > access.log <<'EOF'192.168.1.10 - alice [09/Apr/2026:08:12:03 +0200] "GET /index.html HTTP/1.1" 200 104310.0.0.5 - bob [09/Apr/2026:08:12:44 +0200] "POST /login HTTP/1.1" 401 219192.168.1.10 - alice [09/Apr/2026:08:13:01 +0200] "GET /dashboard HTTP/1.1" 200 512010.0.0.99 - - [09/Apr/2026:08:13:37 +0200] "GET /admin HTTP/1.1" 403 16210.0.0.5 - bob [09/Apr/2026:08:14:02 +0200] "POST /login HTTP/1.1" 200 874172.16.0.3 - charlie [09/Apr/2026:08:14:50 +0200] "GET /api/users/42 HTTP/1.1" 404 145192.168.1.10 - alice [09/Apr/2026:08:15:12 +0200] "DELETE /api/orders/7 HTTP/1.1" 500 302EOF
cat > ventes.csv <<'EOF'produit,region,quantite,prix_unitairelaptop,nord,5,1200serveur,sud,2,3500switch,nord,10,450laptop,est,3,1200serveur,nord,1,3500switch,sud,8,450disque,est,20,80EOFLe délimiteur <<'EOF' est entre guillemets simples volontairement : sans eux, le shell interpréterait les $ et les guillemets présents dans le journal avant même que le fichier soit écrit.
Les champs automatiques
Section intitulée « Les champs automatiques »awk découpe chaque ligne en champs selon un séparateur (espace par défaut) et les numérote :
| Variable | Contenu |
|---|---|
$0 | La ligne entière |
$1 | Premier champ |
$2 | Deuxième champ |
$NF | Dernier champ (NF = nombre de champs) |
NR | Numéro de la ligne courante |
NF | Nombre de champs sur la ligne courante |
Exemple sur un access.log
Section intitulée « Exemple sur un access.log »Le format Combined Log place toujours l'information au même rang : l'adresse du client en premier, le code de statut HTTP en neuvième position. C'est ce qui rend awk utilisable ici sans regex : on désigne une donnée par sa position, pas par sa forme. Le programme entre accolades s'exécute une fois par ligne lue, et print sépare ses arguments par une espace.
awk '{print NR, $1, $9}' access.log1 192.168.1.10 2002 10.0.0.5 4013 192.168.1.10 2004 10.0.0.99 4035 10.0.0.5 2006 172.16.0.3 4047 192.168.1.10 500$1= adresse IP$9= code de statut HTTP (le 9e champ dans le format Combined Log)NR= numéro de ligne
Changer le séparateur avec -F
Section intitulée « Changer le séparateur avec -F »Par défaut, awk sépare les champs sur les espaces. L'option -F change ce séparateur :
Parser /etc/passwd avec -F:
Section intitulée « Parser /etc/passwd avec -F: »Le fichier /etc/passwd liste les comptes locaux du système, un par ligne, avec sept champs séparés par des deux-points. cut -d: -f1,7 ferait la même extraction, mais awk permet en plus de filtrer sur la valeur d'un champ, par exemple ne garder que les comptes dont le shell est /bin/bash. Attention, -F: doit précéder le programme sur la ligne de commande. Placée après, l'option est prise pour un nom de fichier et awk s'arrête sur fatal: cannot open file '-F:' for reading. Vos valeurs différeront des miennes : ce sont les comptes de la machine de test.
awk -F: '{print $1, $7}' /etc/passwdroot /bin/bashdaemon /usr/sbin/nologinbob /bin/bashalice /bin/zshsshd /usr/sbin/nologin$1= nom d'utilisateur$7= shell de connexion (7e champ séparé par:)
Calculer sur un CSV avec -F,
Section intitulée « Calculer sur un CSV avec -F, »# Afficher produit et total (quantité × prix unitaire), en sautant l'en-têteawk -F, 'NR > 1 {print $1, $3*$4}' ventes.csvlaptop 6000serveur 7000switch 4500laptop 3600serveur 3500switch 3600disque 1600NR > 1 saute la première ligne (en-tête). Les champs $3 et $4 sont multipliés directement, awk gère l'arithmétique nativement.
Filtrer avec des conditions
Section intitulée « Filtrer avec des conditions »Un programme awk s'écrit sous la forme condition { action }. Quand la condition est omise, l'action s'applique à toutes les lignes ; quand l'action est omise, awk affiche la ligne entière. Les trois formes de condition qui suivent, numérique, chaîne et regex, couvrent la quasi-totalité des filtrages d'administration.
Conditions numériques
Section intitulée « Conditions numériques »awk traite un champ qui ressemble à un nombre comme un nombre dans une comparaison. C'est la différence décisive avec grep, qui ne connaît que du texte : grep 4 trouverait aussi bien 404 que 1043, alors que $9 >= 400 compare réellement des valeurs.
Le piège arrive quand le champ ne ressemble pas à un nombre. awk bascule alors en comparaison de chaînes, et le résultat surprend : echo abc | awk '$1 >= 400' affiche la ligne, parce que la chaîne "abc" est lexicalement supérieure à "400". Aucun message d'erreur, juste des lignes parasites dans votre résultat. Sur un fichier dont vous ne maîtrisez pas la propreté, forcez la conversion avec $1+0 >= 400 : le +0 impose une comparaison numérique et écarte les valeurs non numériques.
# Requêtes avec code HTTP >= 400 (erreurs)awk '$9 >= 400 {print $1, $9, $7}' access.log10.0.0.5 401 /login10.0.0.99 403 /admin172.16.0.3 404 /api/users/42192.168.1.10 500 /api/orders/7Comparaison de chaînes
Section intitulée « Comparaison de chaînes »L'opérateur == exige une égalité stricte sur la totalité du champ. Ici la difficulté vient du format : dans le Combined Log, la requête est encadrée par des guillemets doubles, donc le sixième champ vaut littéralement "POST avec son guillemet ouvrant collé. La séquence "\"POST" construit cette chaîne dans le programme awk, la barre oblique inverse protégeant le guillemet interne. Si vous cherchez une sous-chaîne plutôt qu'une valeur exacte, utilisez l'opérateur regex présenté juste après.
# Requêtes POST seulementawk '$6 == "\"POST" {print $1, $7, $9}' access.log10.0.0.5 /login 40110.0.0.5 /login 200Filtrer par regex avec ~ et !~
Section intitulée « Filtrer par regex avec ~ et !~ »Les opérateurs ~ et !~ appliquent une expression régulière à un champ précis, ce que grep ne sait pas faire : grep 192.168 remonterait aussi une ligne où cette adresse apparaît dans l'URL ou l'agent utilisateur. Le motif se place entre barres obliques et n'a pas besoin d'être ancré par défaut, d'où le ^ dans le premier exemple pour exiger un début de champ. Notez les points échappés en \. : sans cela, le point de la regex accepte n'importe quel caractère.
# IPs du réseau 192.168 seulementawk '$1 ~ /^192\.168\./ {print $1, $9}' access.log192.168.1.10 200192.168.1.10 200192.168.1.10 500# Exclure les requêtes de aliceawk '$3 !~ /alice/ {print $1, $3, $9}' access.log10.0.0.5 bob 40110.0.0.99 - 40310.0.0.5 bob 200172.16.0.3 charlie 404~: le champ correspond au pattern!~: le champ ne correspond pas au pattern
BEGIN et END, traitement global
Section intitulée « BEGIN et END, traitement global »BEGIN s'exécute avant la première ligne. END s'exécute après la dernière. Utilisés pour les en-têtes, les totaux et les résumés.
Calculer un total avec END
Section intitulée « Calculer un total avec END »C'est le motif à retenir pour tout calcul d'agrégat : accumuler ligne par ligne dans une variable, puis afficher le résultat dans END. Deux détails comptent. awk initialise implicitement toute variable numérique à 0, il n'y a donc rien à déclarer avant la boucle. Et le programme s'étale ici sur plusieurs lignes à l'intérieur d'une même paire de guillemets simples : le shell ne rend la main qu'à la quote fermante, ce qui autorise cette mise en forme lisible. La séquence '\'' insère une apostrophe française dans le texte affiché sans casser cette quote.
awk -F, 'NR == 1 { next }{ total += $3 * $4 lignes++}END { print "Lignes traitées :", lignes print "Chiffre d'\''affaires total :", total, "€"}' ventes.csvLignes traitées : 7Chiffre d'affaires total : 29800 €total += $3 * $4: accumulation dans une variable globalelignes++: compteur de lignes traitées- Le bloc
ENDest appelé une seule fois après toutes les lignes
Tableaux associatifs, compter par valeur
Section intitulée « Tableaux associatifs, compter par valeur »awk supporte nativement les tableaux dont les clés sont des chaînes, l'outil parfait pour compter des occurrences par valeur.
Compter les codes HTTP
Section intitulée « Compter les codes HTTP »Cette commande fait en une ligne ce qui demanderait un sort | uniq -c sur un champ préalablement extrait. La clé du tableau est la valeur lue dans le champ, pas un indice numérique : awk crée l'entrée à la première rencontre et l'incrémente ensuite. Résultat, le nombre de compteurs s'adapte tout seul aux valeurs présentes dans le fichier, sans que vous ayez à connaître à l'avance la liste des codes HTTP.
awk '{codes[$9]++} END {for (c in codes) print c, codes[c]}' access.log | sort200 3401 1403 1404 1500 1codes[$9]++: incrémente le compteur indexé par la valeur du code HTTPfor (c in codes): itère sur toutes les clés du tableau| sort: awk ne garantit pas l'ordre des clés, on trie à la fin
Tableau de synthèse par IP
Section intitulée « Tableau de synthèse par IP »Voici le cas réel qui justifie d'apprendre les tableaux associatifs : repérer d'un coup d'œil quel client génère des erreurs. Le programme tient deux compteurs indexés sur la même clé, l'adresse IP, et les affiche côte à côte. La colonne à surveiller est la troisième : une IP avec beaucoup de requêtes et peu d'erreurs est un utilisateur normal, une IP avec un ratio proche de 1 ressemble à un balayage ou à un client cassé. Le sort final ne peut pas être remplacé par une option d'awk, l'ordre de parcours d'un tableau n'étant pas défini.
awk '{ip[$1]++; if ($9 >= 400) err[$1]++}END { for (i in ip) printf "%-16s %6d %6d\n", i, ip[i], err[i]+0}' access.log | sort -k2 -rn192.168.1.10 3 110.0.0.5 2 1172.16.0.3 1 110.0.0.99 1 1- Deux tableaux parallèles :
ip[]pour le total,err[]pour les erreurs err[i]+0: si la clé n'existe pas, retourne0(pas d'erreur de type)sort -k2 -rn: trier par deuxième colonne (requêtes), décroissant
Reformater avec printf
Section intitulée « Reformater avec printf »print sépare les champs avec l'OFS (espace par défaut). printf donne un contrôle précis sur l'alignement et le format.
awk -F, 'NR > 1 {printf "%-10s %-6s %6d €\n", $1, $2, $3*$4}' ventes.csvlaptop nord 6000 €serveur sud 7000 €switch nord 4500 €laptop est 3600 €serveur nord 3500 €switch sud 3600 €disque est 1600 €Formats printf courants :
| Format | Effet |
|---|---|
%-10s | Chaîne, alignée à gauche, largeur 10 |
%10s | Chaîne, alignée à droite, largeur 10 |
%6d | Entier, largeur 6 |
%.2f | Flottant, 2 décimales |
%s | Chaîne sans largeur fixe |
awk vs les autres outils
Section intitulée « awk vs les autres outils »| Outil | Quand l'utiliser |
|---|---|
grep | Filtrer des lignes par pattern texte, pas de raisonnement sur les champs |
cut | Extraire des colonnes à position fixe ou délimiteur simple, sans calcul |
sed | Transformer du texte, substituer des patterns, modifier in-place |
awk | Filtrer par champ, calculer, compter, reformater, créer des tableaux de synthèse |
| Python | Logique complexe, structures de données riches, fichiers JSON/YAML |
La règle pratique : si vous avez besoin de raisonner sur la valeur d'un champ (pas juste extraire), commencez par awk.
Pièges fréquents
Section intitulée « Pièges fréquents »La première ligne du tableau concerne le shell, pas awk : c'est de loin l'erreur la plus fréquente, parce que le message renvoyé parle de syntaxe awk alors que le programme a déjà été déformé par bash avant d'arriver à l'interpréteur. Les quatre suivantes tiennent au comportement d'awk lui-même et ne déclenchent aucune erreur : le résultat est simplement faux ou incomplet, ce qui est bien plus dangereux dans un script de production. La dernière, NR contre FNR, ne se manifeste que si vous passez plusieurs fichiers à la même commande.
| Piège | Symptôme | Solution |
|---|---|---|
| Guillemets dans le shell | " dans le pattern awk interprété par bash | Toujours encadrer le programme awk avec des '...' |
Confondre print et printf | Saut de ligne manquant avec printf | Ajouter \n explicitement dans printf |
| Clé inexistante dans un tableau | Valeur vide affichée, et la clé est créée au passage (elle apparaît ensuite dans for (k in arr)) | Utiliser arr[k]+0 pour les entiers, arr[k]"" pour les chaînes ; tester avec if (k in arr), qui ne crée rien |
| Ordre des clés d'un tableau | Résultat non trié | Piper vers sort après le bloc END |
| NR vs FNR avec plusieurs fichiers | NR continue de s'incrémenter entre fichiers | Utiliser FNR pour le numéro de ligne dans le fichier courant |
Contrôle de connaissances
Section intitulée « Contrôle de connaissances »Vérifiez que l'essentiel de ce guide est acquis. Les questions portent uniquement sur ce qui vient d'être expliqué ici.
Contrôle de connaissances
Validez vos connaissances avec ce quiz interactif
Informations
- Le chronomètre démarre au clic sur Démarrer
- Questions à choix multiples, vrai/faux et réponses courtes
- Vous pouvez naviguer entre les questions
- Les résultats détaillés sont affichés à la fin
Lance le quiz et démarre le chronomètre
Vérification
(0/0)Profil de compétences
Quoi faire maintenant
Ressources pour progresser
Des indices pour retenter votre chance ?
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications
À retenir
Section intitulée « À retenir »$1,$NF,NR, les variables de base à connaître par cœur-F:ou-F,, change le séparateur de champ$3 >= 400, conditions numériques directes sur un champ$1 ~ /regex/et$1 !~ /regex/, filtrage par pattern sur un champtableau[$clé]++, compter des occurrences par valeurBEGIN/END, avant la première ligne / après la dernièreprintf "%-10s %6d\n", formater une sortie en tableau aligné| sort, toujours trier aprèsfor (k in tableau)si l'ordre compte
Pour aller plus loin
Section intitulée « Pour aller plus loin »- Référence awk : Variables internes, fonctions, getline, OFMT, CONVFMT, le condensé complet des options awk.