Transformer du texte : introduction à sed et awk
Notions théoriques
Quand grep et cut ne suffisent plus
grep cherche, cut extrait une colonne fixe. Mais dès qu'il faut modifier du texte, ou raisonner sur des colonnes mal alignées (espaces multiples, tabulations variables) et faire des calculs, deux outils plus puissants prennent le relais : sed (éditeur de flux) et awk (langage de traitement par colonnes).
sed : l'éditeur de flux
sed lit un texte ligne par ligne et applique une transformation, sans jamais ouvrir d'éditeur interactif.
sed 's/ancien/nouveau/' fichier.txt
s/ancien/nouveau/: substitue la première occurrence d'ancienparnouveau, sur chaque ligne.s/ancien/nouveau/g: le suffixeg(global) remplace toutes les occurrences de la ligne, pas seulement la première.s/ancien/nouveau/I: le suffixeIignore la casse.
Si le motif recherché contient lui-même un /, changez de séparateur pour éviter d'avoir à l'échapper :
sed 's|/var/log|/srv/log|' fichier.txt
Sélectionner des lignes par adresse :
sed '2d' fichier.txt # supprime la ligne 2
sed '/^#/d' fichier.txt # supprime les lignes commençant par # (les commentaires)
sed -n '/ERROR/p' fichier.txt # affiche seulement les lignes contenant ERROR
sed -n '1,10p' fichier.txt # affiche seulement les lignes 1 à 10
L'option -n coupe l'affichage automatique de chaque ligne : sans elle, sed -n '/ERROR/p' afficherait chaque ligne deux fois.
sed -i modifie le fichier en place, directement, sans confirmation ni sauvegarde automatique. Testez toujours votre commande sed sans -i d'abord (la sortie s'affiche simplement à l'écran, le fichier reste intact), et une fois certain du résultat, utilisez sed -i.bak 's/.../.../g' fichier : le suffixe .bak crée une copie de sauvegarde avant modification.
awk : traiter par colonnes et par calcul
awk découpe chaque ligne en champs, automatiquement séparés par les espaces (y compris multiples) — là où cut échoue sur des colonnes mal alignées.
awk '{ print $1, $3 }' fichier.txt
$1,$2... désignent les champs de la ligne courante,$0désigne la ligne entière.NF(Number of Fields) contient le nombre de champs de la ligne courante.NR(Number of Records) contient le numéro de la ligne courante.-F':'change le séparateur de champs (utile pour/etc/passwd, séparé par:).
awk -F: '{ print $1 }' /etc/passwd
Structure motif { action } : awk peut filtrer avant d'agir, comme grep, mais avec des comparaisons de champs :
awk -F: '$3 >= 1000 { print $1 }' /etc/passwd
(affiche le nom des comptes dont l'UID, 3e champ, est supérieur ou égal à 1000 — les comptes "humains", par convention Linux)
BEGIN et END, calculs et mise en forme :
awk '{ somme += $5 } END { print "Total :", somme }' fichier.txt
awk '{ printf "%-15s %5d\n", $1, $2 }' fichier.txt
BEGIN { } s'exécute une seule fois avant de lire la première ligne, END { } une seule fois après la dernière — typiquement pour initialiser ou afficher un total. printf permet un alignement précis (%-15s = chaîne alignée à gauche sur 15 caractères, %5d = nombre aligné à droite sur 5 caractères), contrairement à print qui se contente de séparer les valeurs par des espaces.
Récapitulatif : quel outil pour quel besoin ?
| Besoin | Outil |
|---|---|
| Chercher une ligne contenant un motif | grep |
| Extraire une colonne à séparateur fixe et unique | cut |
| Remplacer du texte, supprimer des lignes | sed |
| Calculer, formater, filtrer par colonnes mal alignées | awk |
Ni sed ni awk ne sont adaptés pour analyser du JSON ou du HTML : ce sont des formats structurés que ces outils, pensés pour du texte ligne par ligne, interprètent mal dès que la structure devient complexe (guillemets imbriqués, accolades sur plusieurs lignes...). Pour du JSON, l'outil dédié est jq, hors du périmètre de ce cours.
Exemple pratique
# Lister les comptes "humains" (UID >= 1000) et leur dossier personnel
awk -F: '$3 >= 1000 { printf "%-15s %s\n", $1, $6 }' /etc/passwd
# Anonymiser les adresses IP d'un journal d'accès avant de le partager
sed -E 's/([0-9]{1,3}\.){3}[0-9]{1,3}/x.x.x.x/g' access.log > access_anonyme.log
Test de mémorisation/compréhension
TP pour réfléchir et résoudre des problèmes
Nous ajoutons à sauvegarde.sh un journal CSV de ses exécutions, exploité avec awk, et corrigeons sa configuration avec sed.
Étape 1 — Écrire une ligne CSV par sauvegarde
Utilisez >> (ajout en fin de fichier) et non > (écrasement) pour un fichier de journal : chaque exécution doit s'ajouter à l'historique, pas effacer les précédentes.
Étape 2 — Calculer le volume total avec awk
Dès qu'un traitement dépasse la simple extraction de colonne (ici, additionner des tailles), awk devient plus adapté que cut, qui ne sait qu'extraire.
Étape 3 — Filtrer les archives d'un jour donné
awk fonctionne dans son propre monde de variables, séparé du shell. -v jour="$jour" est la façon propre de lui transmettre une valeur calculée par le script, plutôt que de bricoler une concaténation de chaînes.
Étape 4 — Corriger la configuration avec sed
sed -i.bak plutôt que sed -i tout court : en cas d'erreur dans votre expression, vous conservez une copie du fichier original pour revenir en arrière immédiatement.