awk est le couteau suisse du traitement de données en ligne de commande. Là où grep filtre des lignes entières et cut extrait des colonnes fixes, awk comprend la structure des données : il découpe chaque ligne en champs, applique des conditions par champ, accumule des valeurs 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 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 »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: »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 »Conditions numériques
Section intitulée « Conditions 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 »# 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 !~ »# 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 »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 »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 »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 »| 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 | Erreur ou valeur vide | Utiliser arr[k]+0 pour les entiers, arr[k]"" pour les chaînes |
| 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 |
À 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