Skip to content

awk — Manipulation de contenus (bases et avancé)

Table des matières

Introduction

awk est un "couteau suisse" pour analyser, transformer et reporter des données texte. Il lit l’entrée ligne par ligne, découpe chaque ligne en champs, applique des motifs (patterns) et exécute des actions. On peut filtrer, agréger, faire des calculs, formater des rapports, le tout en une commande concise ou via un petit script.

  • Entrée: lignes de texte (fichiers, stdin, sortie d’un pipe)
  • Séparation: enregistrements = lignes, champs = colonnes (séparées par FS)
  • Motifs: regex, conditions, plages, combinaisons logiques
  • Actions: print, printf, calculs, variables, tableaux, fonctions

Fonctionnement

  • awk lit l’entrée ligne par ligne (appelée "enregistrement"), stockée dans $0.
  • Chaque ligne est découpée en champs selon le séparateur de champs FS (par défaut: espaces/tabulations). Les champs sont accessibles avec $1, $2, …, $NF (NF = nombre de champs).
  • On peut spécifier des "motifs" (pattern) pour sélectionner les lignes, puis écrire des "actions" à exécuter.

Syntaxes usuelles:

sh
awk [-F] 'pattern { action }' fichier1 fichier2 ...

awk -F ':' '{ print $1, $3 }' /etc/passwd      # -F configure FS pour utiliser ':' comme séparateur

awk -f script.awk fichiers...                  # utilise un script externe

Notes:

  • Sans fichier, awk lit sur l’entrée standard (peut être placé après un pipe).
  • -F change le séparateur d’entrée (FS). Exemple: -F ',' pour un CSV pour utiliser la virgule comme séparateur.

Variables intégrées essentielles

  • $0: enregistrement entier (la ligne courante)
  • $1 .. $NF: champs individuels; NF = nombre de champs
  • FS: Field Separator (séparateur d’entrée) — par défaut espace/tab
  • OFS: Output Field Separator (séparateur de champs en sortie) — par défaut espace
  • RS: Record Separator (séparateur d’enregistrements) — par défaut saut de ligne
  • ORS: Output Record Separator — par défaut saut de ligne
  • NR: NombRe global de l’enregistrement courant (compte sur tous les fichiers)
  • FNR: NombRe dans le Fichier courant (se réinitialise à 1 par fichier)
  • FILENAME: nom du fichier en cours

On peut également affecter des variables utilisateur à la volée: sum += $3, seuil=60, etc.

Exemples simples

Afficher toutes les lignes d’un fichier :

bash
awk '{ print }' fichier.txt

Afficher la 3ème colonne uniquement :

bash
awk '{ print $3 }' fichier.txt

Afficher la dernière colonne :

bash
awk '{ print $NF }' fichier.txt

Changer le séparateur de champs (ex : fichier CSV) :

bash
awk -F';' '{ print $1, $3 }' fichier.csv

Afficher le numéro de ligne suivi du contenu :

bash
awk '{ print NR, $0 }' fichier.txt

Filtrer avec motifs et expressions régulières

Motif simple sur la ligne

sh
$ awk '/erreur/ { print $0 }' fichier.log   # imprime les lignes contenant "erreur"

Expressions régulières (regex)

Filtre avec motif regex qui s'applique à la ligne entière ($0):

sh
$ awk '/^J.*$/ { print $0 }' noms.txt  # affiche les lignes commençant par J

$ awk '/[0-9]{3}-[0-9]{2}-[0-9]{4}/ { print $0 }' data.txt  # lignes avec format 000-00-0000

Filtrer sur un champ avec ~ et !~

Filtrer avec motif regex appliqué à un champ spécifique:

Exemple data.txt :

1 emile user
2 paul editor
3 evelyne admin
sh
$ awk '$2 ~ /^e.*/ { print $2 }' data.txt    # le champ 2 matche la regex (commence par 'e')
emile
evelyne

$ awk '$3 !~ /admin/ { print $0 }' data.txt # le champ 3 ne contient pas "admin"
1 emile user
2 paul editor

Opérateurs logiques et de plage

  • ET logique: cond1 && cond2
  • OU logique: cond1 || cond2
  • Égalité: cond1 == cond2
  • Négation: !cond
  • Plage (range): motif_debut, motif_fin sélectionne de la 1re ligne qui correspond à motif_debut jusqu’à la 1re ligne qui correspond à motif_fin (inclusivement).

Exemples:

sh
# Filtrer les lignes où le 2ème champ vaut exactement "motif"
awk '$2 == "motif"' fichier.txt

# Afficher les lignes entre "START" et "END"
$ awk '/START/,/END/ { print }' rapport.txt

# Filtrer les lignes où le 3e champ > 60 et le 1er champ contient "Dupont"
$ awk '$3 > 60 && $1 ~ /Dupont/' notes.csv

# Filter les lignes où le 4e champ est "admin" ou "editor"
$ awk '$4 == "admin" || $4 == "editor"' users.txt

Blocs BEGIN et END

Ces blocs permettent d’exécuter du code avant la lecture (BEGIN) et après (END):

Exemple notes.csv :

Nom,Prenom,Note
Dupont,Jean,75
Martin,Claire,58
Durand,Pierre,82
sh
# Initialisation avant traitement et résumé après
# FS="," pour la séparation CSV
# OFS="\t" pour sortie tabulée
$ awk 'BEGIN { FS=","; OFS="\t"; print "Nom", "Note" } $3>60 { print $1, $3 } END { print "— Fin —" }' notes.csv
Nom     Note
Dupont  75
Durand  82
 Fin

Usages typiques:

  • Initialiser FS/OFS/RS/ORS, variables, en-têtes de colonnes (BEGIN)
  • Cumuler des compteurs/sommes puis imprimer un bilan (END)

Opérateurs arithmétiques et de comparaison

Arithmetic: + - * / % ^, avec affectations composées += -= *= /= %= ^=, et pré/post ++ --.

Comparaison: == != < <= > >= (les conditions évaluent à vrai/faux).

Exemples:

sh
$ awk '{ i=2; i+=3; print i }' # = 5

# Compter et sommer les valeurs ≥ 10 dans le 3e champ puis afficher compteur, somme, et moyenne
$ awk '$3>=10 { compteur++; somme+= $3 } END { print compteur, somme, somme/compteur }'

Formatage de la sortie

Affichage: print vs printf

  • print sépare les champs par OFS (espace par défaut) et termine par ORS (\n par défaut)
  • printf utilise des formats du langage C (%s %d %.2f, etc.) et ne rajoute pas automatiquement de fin de ligne

Formats du langage C

awk utilise les mêmes spécificateurs de format que le langage C pour printf:

  • %s: chaîne de caractères
  • %d ou %i: entier signé
  • %u: entier non signé
  • %f: flottant (décimal)
  • %e: notation scientifique
  • %g: format flottant compact (choisit entre %f et %e)
  • %x / %X: entier en hexadécimal (affiche en minuscule ou majuscule)
  • Modificateurs:
    • Largeur minimale: %10s (chaîne sur au moins 10 caractères)
    • Précision: %.2f (2 décimales)
    • Alignement à gauche: %-10s
  • Zéros de bourrage: %05d (entier sur 5 chiffres, rempli de zéros)
  • Flags: + (affiche le signe), - (alignement à gauche)
sh
$ awk 'BEGIN{OFS=","} { print $1,$2,$3 }' data.txt
Dupont,Jean,75
Martin,Claire,58
Durand,Pierre,82
sh
$ cat prix.txt
ProduitA 01 12.5
ProduitB 02 9.99
ProduitAvecUnNomLong 03 100.0
sh
# Colonnes alignées: nom sur 20, montant sur 7 avec 2 décimales
# \n pour le saut de ligne
$ awk '{ printf("%-20s %7.2f\n", $1, $3) }' prix.txt
ProduitA               12.50
ProduitB                9.99
ProduitAvecUnNomLong  100.00
sh
# Colonnes alignées: nom sur 12, entier sur 5 bourré de zéros, montant sur 2 décimales
$ awk '{ printf("%-12s %05d %8.2f\n", $1, $2, $3) }' prix.txt
ProduitA     00001    12.50
ProduitB     00002     9.99
ProduitAvecUnNomLong 00003   100.00
sh
# Signes et formats flottants
$ awk '{ printf("%+8.3f  %e  %g\n", $3, $3, $3) }' prix.txt
 +12.500  1.250000e+01  12.5
  +9.990  9.990000e+00  9.99
+100.000  1.000000e+02  100

Chaînes utiles: "\t" (tab), "\n" (saut de ligne).

La concaténation se fait par simple juxtaposition: "Total:" total.

Exemples avec concaténation :

sh
$ awk '{ total += $3 } END { print "Total des prix: " total }'  prix.txt
Total des prix: 122.49

Tableaux associatifs

Les tableaux associatifs permettent de stocker des paires clé-valeur. Les clés sont des chaînes (ou des combinaisons de champs), et les valeurs peuvent être des nombres ou des chaînes.

Exemple: compter les occurrences d’un mot dans un texte

sh
$ awk '{ for(i=1; i<=NF; i++) freq[$i]++ } END { for(mot in freq) print mot, freq[mot] }' texte.txt

Calculs et agrégations

Somme d'une colonne

sh
$ awk '{ sum += $3 } END { print "Somme:", sum }' fichier.txt

Moyenne d'une colonne

sh
$ awk '{ sum += $3; count++ } END { if (count > 0) print "Moyenne:", sum/count; else print "Aucune donnée" }' fichier.txt

minimum ou maximum

sh
$ awk 'NR==1 || $3 < min { min = $3 } END { print "Min:", min }' fichier.txt
$ awk 'NR==1 || $3 > max { max = $3 } END { print "Max:", max }' fichier.txt

Compter suivant une condition

sh
$ awk '$3 > 50 { count++ } END { print "Nombre de lignes avec $3 > 50:", count }' fichier.txt

Calculs entre colonnes

sh
$ awk '{ total += $2 * $3 } END { print "Total:", total }' fichier.txt

Fonctions intégrées courantes

  • Longueurs et sous-chaînes: length(s), substr(s, debut, longueur)
  • Remplacements: sub(/re/, repl, s), gsub(/re/, repl, s)
  • Casse: tolower(s), toupper(s)
  • Découpage: split(s, tab, sep) — remplit le tableau tab et retourne le nombre d’éléments
  • Formats: sprintf(fmt, ...)
  • Maths: sin, cos, atan2, exp, log, sqrt, rand, srand

Exemples détaillés

length et substr

  • length(s) retourne la longueur de la chaîne s. Si s est omis, c’est la longueur de $0 (la ligne courante) qui est retournée.
  • substr(s, debut, longueur) extrait une sous-chaîne de s à partir de l’index debut (1-based) sur longueur caractères.

Entrée mots.txt:

abricot rouge
poire verte
kiwi jaune

Commande:

sh
$ awk '{ print length($0), substr($1,1,3), substr($2,length($2)-1) }' mots.txt

Sortie (exemple):

13 abr ne
11 poi te
10 kwi ne

sub vs gsub

  • sub(/re/, repl, s) remplace la 1re occurrence de la regex /re/ par repl dans la chaîne s.
  • gsub(/re/, repl, s) remplace toutes les occurrences de la regex /re/ par repl dans la chaîne s, et retourne le nombre de remplacements effectués.
sh
$ echo 'foo foo bar foo' |
	awk '{ s=$0; sub(/foo/, "FOO", s); print s; }'   # remplace la 1re occurrence seulement
FOO foo bar foo

$ echo 'foo foo bar foo' |
	awk '{ s=$0; n=gsub(/foo/, "FOO", s); print s, "| remplacements:", n }'
FOO FOO bar FOO | remplacements: 3

split (découpage dans un tableau)

split(s, tab, sep) divise la chaîne s en utilisant le séparateur sep, remplit le tableau tab (indexé à partir de 1) et retourne le nombre d’éléments.

sh
$ echo 'jean,dupont,75' | awk '{
	n = split($0, a, ",");        # a[1]=jean, a[2]=dupont, a[3]=75
	printf("%s %s a %d éléments, note=%s\n", a[1], a[2], n, a[3]);
}'
jean dupont a 3 éléments, note=75

tolower et toupper

sh
$ echo 'Jean DUPONT' | awk '{ print tolower($0), "|", toupper($1) }'
jean dupont | JEAN

sprintf (préparer une chaîne formatée)

  • sprintf(fmt, ...) formate une chaîne selon fmt et retourne la chaîne résultante (sans l’imprimer).
sh
$ awk 'BEGIN { total=122.49; msg=sprintf("Total des prix: %.2f", total); print msg }'
Total des prix: 122.49

Exemples pratiques

CSV: moyenne des notes ≥ 60

Objectif: lire un CSV "Nom,Prenom,Note" et calculer la moyenne des étudiants qui passent.

sh
$ awk -F, 'BEGIN{pass=0;sum=0}
					$3+0 >= 60 { pass++; sum += $3+0 }
					END{ if(pass) printf("Moyenne des %d admis: %.2f\n", pass, sum/pass); else print "Aucun admis" }' notes.csv

Remarques:

  • L’opérateur +0 force l’interprétation numérique (utile si les décimales utilisent un point dans les données).
  • On peut adapter FS et OFS selon le fichier.

ps: filtrer et formater

sh
# Afficher USER, PID et COMMAND des processus librewolf avec formatage
$ ps aux | awk 'NR==1 || /librewolf/ { printf("%-10s %6s %s\n", $1, $2, $11) }'
USER          PID COMMAND
zil          1246 /usr/lib/librewolf/librewolf
zil          1869 /usr/lib/librewolf/librewolf

NR==1 laisse passer l’en-tête. Filtrage simple sur la ligne, puis formatage.

Logs web: top IP

sh
# Afficher le nombre de hits par IP (champ 1) trié décroissant
$ awk '{ ip=$1; hits[ip]++ } END { for (i in hits) printf("%7d %s\n", hits[i], i) }' access.log | sort -nr
590 192.12.116.101:80
30 192.12.116.102:80

###Agrégation par groupe (CSV)

sh
cat ventes.csv
Client,Produit,Montant
Alice,ProduitA,120.50
Bob,ProduitB,75.00
Alice,ProduitA,30.00
Bob,ProduitC,45.25
Charlie,ProduitB,60.00
sh
$ awk -F, 'NR>1 { montant[$2]+= $3 } END { for (g in montant) printf("%s => %.2f\n", g, montant[g]) }' ventes.csv
ProduitA => 150.50
ProduitB => 135.00
ProduitC => 45.25
  • NR>1 saute l’en-tête.

Utiliser des scripts awk avec -f

Pour des traitements plus longs, placez le programme awk dans un fichier et exécutez-le avec -f.

Contenu de stats.awk:

awk
BEGIN {
	FS=","; OFS=",";
	print "Nom","Note";
}

$3+0 >= 60 {
	admis++; somme += $3+0; print $1, $3
}

END {
	if (admis) printf("Moyenne des %d admis: %.2f\n", admis, somme/admis);
}

Exécution:

sh
awk -f stats.awk notes.csv

Pièges et bonnes pratiques

  • Toujours régler/contrôler FS/OFS sur des données structurées (CSV/TSV)
  • Forcer l’interprétation numérique au besoin: +0, ou ($3+0)
  • Préserver l’en-tête: NR==1 {print; next} sur CSV avec en-tête
  • Préférer printf pour un alignement stable dans les rapports
  • Sur gros volumes: limiter les actions dans la boucle, agréger puis formater en END

Pratique 💃

Voir les exercices sur Gitlab: https://gitlab.com/16d/420-16d-exercices/-/tree/main/awk

.