Cours Linux / Rechercher et traiter du texte avec grep, sort, uniq, cut et wc
Utilisez grep pour sélectionner des lignes, cut pour extraire des champs, sort pour ordonner les résultats, uniq pour regrouper les répétitions voisines et wc pour compter. En les reliant par un pipe, vous pouvez obtenir le nombre d’occurrences de chaque nom dans un petit fichier structuré. Cette leçon compare les sorties sur cinq lignes connues, puis modifie une seule ligne d’entrée et rétablit les données initiales.
Les exemples utilisent Bash et les outils GNU dans le Linux de pratique. Aucun sudo n’est nécessaire. Un pipe, écrit |, transmet la sortie standard d’une commande à l’entrée standard de la suivante : les noms extraits deviennent ainsi les lignes à trier puis à compter.
Créer cinq lignes dans un nouveau dossier
Chaque ligne contient un nom, deux-points et un état. Utilisez un dossier linux-course-12-practice neuf dans votre répertoire personnel. S’il existe déjà, choisissez un autre nom à la ligne candidat : le premier mkdir ne doit pas réutiliser d’anciens fichiers.
textes=
candidat="$HOME/linux-course-12-practice"
if mkdir -- "$candidat" &&
printf 'alpha:ready\nbeta:waiting\nalpha:done\ngamma:ready\nbeta:ready\n' > "$candidat/records.txt"; then
textes=$candidat
printf 'Fichier : %s\n' "$textes/records.txt"
else
printf '%s\n' 'Préparation échouée : choisir un dossier neuf et vérifier avant de continuer.' >&2
fi
La variable textes n’est renseignée que lorsque le dossier et le fichier ont été créés. Une erreur peut laisser un dossier partiellement préparé : examinez le message avant de recommencer avec un nouveau nom. Gardez ce terminal ouvert et ne redéfinissez pas textes vers un autre emplacement. Les blocs suivants vérifient que cette variable n’est pas vide.
La redirection > écrit dans le fichier et peut remplacer un contenu existant. Elle est utilisée ici uniquement dans le dossier neuf. \n produit une fin de ligne ; vérifiez les données avant tout traitement :
test -n "$textes" && cat -- "$textes/records.txt"
alpha:ready
beta:waiting
alpha:done
gamma:ready
beta:ready
Vous devez obtenir exactement ces cinq lignes, dans cet ordre. Les mots ready, waiting et done sont des valeurs de démonstration. Si votre fichier diffère, corrigez la préparation avant de comparer les résultats.
Sélectionner les lignes correspondantes avec grep
grep affiche par défaut les lignes qui correspondent au motif. L’option -n ajoute le numéro de la ligne dans le fichier d’origine :
test -n "$textes" && grep -n 'ready' -- "$textes/records.txt"
Le résultat contient trois lignes :
1:alpha:ready
4:gamma:ready
5:beta:ready
Les numéros 1, 4 et 5 ne renumérotent pas la sélection : ils situent les correspondances dans l’entrée. waiting et done ne contiennent pas ready. Une recherche de ready correspond à une sous-chaîne ; sur d’autres données, elle peut également sélectionner un mot plus long qui la contient.
Le motif de grep est normalement une expression régulière, c’est-à-dire une notation de recherche où certains caractères ont un sens spécial. Pour une chaîne à interpréter littéralement, choisissez -F. Vous pouvez vérifier cette forme sur la même entrée :
test -n "$textes" && grep -Fn 'ready' -- "$textes/records.txt"
Vous retrouvez les trois mêmes lignes : ready ne contient ici aucun caractère spécial qui change le résultat. Les apostrophes protègent le motif du shell ; elles ne désactivent pas à elles seules les expressions régulières de grep.
Dans ces commandes GNU grep sans -q, l’état de sortie vaut normalement 0 si une ligne a été sélectionnée, 1 si aucune ne l’a été et 2 en cas d’erreur. Une sortie vide n’est donc pas à interpréter sans examiner le message et l’état. Le manuel GNU grep décrit les motifs, les numéros et cette distinction ; le guide français de grep développe les recherches à adapter à d’autres fichiers.
Extraire le champ qui représente le nom avec cut
cut -d: -f1 prend deux-points comme séparateur et extrait le premier champ de chaque ligne. Les numéros de champs commencent à 1 :
test -n "$textes" && cut -d: -f1 -- "$textes/records.txt"
alpha
beta
alpha
gamma
beta
Vous avez toujours cinq lignes, mais seulement les noms. Les deux lignes alpha:ready et alpha:done donnent maintenant la même valeur alpha : c’est ce choix d’unité qui permettra de compter les noms indépendamment de leur état.
Le manuel GNU cut précise qu’une ligne sans séparateur est normalement recopiée entière avec -f ; -s permet d’omettre ces lignes. N’appliquez pas ce découpage simple à un fichier CSV complexe dont les guillemets peuvent contenir un séparateur ou un saut de ligne : cut ne fournit pas cette analyse du format CSV.
Comparer les répétitions voisines et les comptes globaux
uniq regroupe uniquement les lignes identiques adjacentes. Sans tri préalable, les deux alpha et les deux beta de notre liste restent séparés. Observez d’abord ce cas :
test -n "$textes" && (
set -o pipefail
cut -d: -f1 -- "$textes/records.txt" | uniq -c
)
Chaque nom reçoit le compte 1, dans l’ordre alpha, beta, alpha, gamma, beta. -c compte les occurrences de chaque groupe voisin ; il n’a pas parcouru une table de noms déjà rencontrés pour les réunir.
Ajoutez maintenant sort entre l’extraction et uniq :
test -n "$textes" && (
set -o pipefail
cut -d: -f1 -- "$textes/records.txt" | LC_ALL=C sort | uniq -c
)
2 alpha
2 beta
1 gamma
Les comptes sont alpha 2, beta 2, gamma 1. Les espaces devant les nombres sont une présentation de uniq, pas une donnée à recopier dans records.txt. L’affectation LC_ALL=C s’applique ici à sort pour choisir un ordre reproductible adapté à ces noms ASCII. Le tri d’un texte accentué dépend des règles de comparaison de la locale choisie ; C ne remplace pas un tri linguistique approprié à chaque langue.
Les parenthèses limitent set -o pipefail à ce sous-shell Bash. Cette option permet au groupe de signaler l’échec d’une commande du pipe, au lieu de se fier seulement à la dernière. Elle ne rend pas un résultat partiel correct et n’explique pas l’erreur : lisez aussi les diagnostics et contrôlez chaque étape. Le manuel Bash des pipelines précise la transmission des données et le calcul de cet état.
Le manuel GNU sort détaille le tri et les locales ; le manuel GNU uniq confirme la condition d’adjacence. Si vous triez directement les lignes complètes de records.txt, alpha:ready et alpha:done restent différentes. Extraire le bon champ est donc aussi important que placer sort avant uniq.
Compter les fins de ligne, les mots et les octets avec wc
wc compte selon l’option choisie. Pour ce fichier terminé par un saut de ligne à chaque enregistrement, -l doit indiquer 5, suivi du chemin fourni :
test -n "$textes" && wc -l -- "$textes/records.txt"
-l compte les caractères de fin de ligne. Une dernière portion de texte sans saut final n’ajoute donc pas une unité. Vous pouvez observer ce cas sans créer ni modifier de fichier :
printf '%s' 'alpha' | wc -l
Le résultat est 0, même si alpha contient du texte. Ce cas explique certaines différences entre le nombre de lignes visibles dans un éditeur et un comptage wc -l.
- wc -w compte les groupes non vides séparés par des espaces blancs selon les règles de l’outil et de la locale. Dans nos cinq lignes, deux-points ne sépare pas deux « mots » pour wc : le compte est 5.
- wc -c compte les octets, y compris les fins de ligne.
- wc -m compte les caractères selon la locale. Avec un texte correctement interprété en UTF-8, un caractère accentué peut occuper plusieurs octets : le compte d’octets et le compte de caractères peuvent alors différer.
Le manuel GNU wc définit ces unités et les conditions de locale. Le guide français de wc permet d’approfondir les différences entre lignes, mots, caractères et octets.
Ajouter une seule occurrence, comparer et rétablir les cinq lignes
Modifiez uniquement notre fichier de démonstration en ajoutant une nouvelle ligne beta:ready. >> ajoute à la fin ; cette opération écrit dans le fichier, contrairement aux consultations précédentes :
test -n "$textes" &&
printf 'beta:ready\n' >> "$textes/records.txt"
Relancez le même comptage, puis vérifiez le nombre total de fins de ligne :
test -n "$textes" && (
set -o pipefail
cut -d: -f1 -- "$textes/records.txt" | LC_ALL=C sort | uniq -c
)
test -n "$textes" && wc -l -- "$textes/records.txt"
Vous devez retrouver alpha 2, beta 3, gamma 1, puis un total de 6. Si beta augmente davantage, vous avez probablement répété l’ajout ; examinez cat avant de conclure à une erreur de uniq.
Rétablissez ensuite exactement les données initiales. Cette réécriture est réservée au fichier jetable de l’atelier :
test -n "$textes" &&
printf 'alpha:ready\nbeta:waiting\nalpha:done\ngamma:ready\nbeta:ready\n' > "$textes/records.txt" &&
cat -- "$textes/records.txt"
Après avoir comparé les cinq lignes avec l’entrée du début, répétez le bloc de comptage précédent : alpha doit revenir à 2, beta à 2, gamma à 1, et wc -l à 5. Vous pouvez conserver ce dossier pour refaire l’expérience ; aucune suppression n’est nécessaire.
Vérifier le traitement dans le bon ordre
| Question | Outil | Point à contrôler |
|---|---|---|
| Quelles lignes correspondent ? | grep | Motif régulier ou chaîne littérale ; correspondance attendue |
| Quelle donnée représente un élément ? | cut | Séparateur, champ et traitement des lignes sans séparateur |
| Comment placer ensemble les valeurs identiques ? | sort | Unité triée et locale |
| Combien de fois chaque groupe voisin apparaît-il ? | uniq -c | Adjacence des doublons avant le comptage |
| Quelle quantité faut-il mesurer ? | wc | Fins de ligne, mots, caractères ou octets |
Si un pipe ne donne pas le résultat attendu, affichez d’abord le fichier connu avec cat, puis exécutez cut seul et vérifiez ses cinq noms. Comparez ensuite le résultat trié avant d’ajouter uniq. Cette progression localise le changement de données : une erreur de séparateur, de motif ou d’entrée ne se corrige pas simplement en répétant le comptage final.




