Appearance
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
awklit 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 externeNotes:
- Sans fichier,
awklit sur l’entrée standard (peut être placé après un pipe). -Fchange 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 champsFS: Field Separator (séparateur d’entrée) — par défaut espace/tabOFS: Output Field Separator (séparateur de champs en sortie) — par défaut espaceRS: Record Separator (séparateur d’enregistrements) — par défaut saut de ligneORS: Output Record Separator — par défaut saut de ligneNR: 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.txtAfficher la 3ème colonne uniquement :
bash
awk '{ print $3 }' fichier.txtAfficher la dernière colonne :
bash
awk '{ print $NF }' fichier.txtChanger le séparateur de champs (ex : fichier CSV) :
bash
awk -F';' '{ print $1, $3 }' fichier.csvAfficher le numéro de ligne suivi du contenu :
bash
awk '{ print NR, $0 }' fichier.txtFiltrer 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-0000Filtrer 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 adminsh
$ 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 editorOpérateurs logiques et de plage
- ET logique:
cond1 && cond2 - OU logique:
cond1 || cond2 - Égalité:
cond1 == cond2 - Négation:
!cond - Plage (range):
motif_debut, motif_finsélectionne de la 1re ligne qui correspond àmotif_debutjusqu’à 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.txtBlocs 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,82sh
# 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
printsépare les champs parOFS(espace par défaut) et termine parORS(\n par défaut)printfutilise 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%dou%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
- Largeur minimale:
- 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,82sh
$ cat prix.txt
ProduitA 01 12.5
ProduitB 02 9.99
ProduitAvecUnNomLong 03 100.0sh
# 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.00sh
# 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.00sh
# 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 100Chaî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.49Tableaux 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.txtCalculs et agrégations
Somme d'une colonne
sh
$ awk '{ sum += $3 } END { print "Somme:", sum }' fichier.txtMoyenne d'une colonne
sh
$ awk '{ sum += $3; count++ } END { if (count > 0) print "Moyenne:", sum/count; else print "Aucune donnée" }' fichier.txtminimum 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.txtCompter suivant une condition
sh
$ awk '$3 > 50 { count++ } END { print "Nombre de lignes avec $3 > 50:", count }' fichier.txtCalculs entre colonnes
sh
$ awk '{ total += $2 * $3 } END { print "Total:", total }' fichier.txtFonctions 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 tableautabet 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înes. Sisest omis, c’est la longueur de$0(la ligne courante) qui est retournée.substr(s, debut, longueur)extrait une sous-chaîne desà partir de l’indexdebut(1-based) surlongueurcaractères.
Entrée mots.txt:
abricot rouge
poire verte
kiwi jauneCommande:
sh
$ awk '{ print length($0), substr($1,1,3), substr($2,length($2)-1) }' mots.txtSortie (exemple):
13 abr ne
11 poi te
10 kwi nesub vs gsub
sub(/re/, repl, s)remplace la 1re occurrence de la regex/re/parrepldans la chaînes.gsub(/re/, repl, s)remplace toutes les occurrences de la regex/re/parrepldans la chaînes, 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: 3split (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=75tolower et toupper
sh
$ echo 'Jean DUPONT' | awk '{ print tolower($0), "|", toupper($1) }'
jean dupont | JEANsprintf (préparer une chaîne formatée)
sprintf(fmt, ...)formate une chaîne selonfmtet 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.49Exemples 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.csvRemarques:
- L’opérateur
+0force l’interprétation numérique (utile si les décimales utilisent un point dans les données). - On peut adapter
FSetOFSselon 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/librewolfNR==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.00sh
$ 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.25NR>1saute 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.csvPièges et bonnes pratiques
- Toujours régler/contrôler
FS/OFSsur 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
printfpour 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