Aller au contenu
Lire et éditer du texte

Lire et éditer du texte

100 Comprendre ⏱ 1 h 15 linuxbashubuntu

À la fin, vous saurez

  • Afficher un fichier entier, une partie, ou le suivre en temps réel, y compris à travers une rotation de journal
  • Résumer un journal avec wc, sort, uniq, cut et grep
  • Comparer deux versions d'un fichier avec diff -u et lire le résultat
  • Reconnaître et corriger un fichier aux fins de ligne Windows ou dans un mauvais encodage
  • Modifier un fichier avec nano ou vim, et quitter vim sans dommage
  • Modifier un fichier de configuration système avec sudoedit, en sauvegardant et en vérifiant

Prérequis

Testé avec bash 5.2.21 coreutils 9.4 diffutils 3.10 grep 3.11 less 590 nano 7.2 ubuntu 24.04 vim 9.1 , vérifié le 5 octobre 2026

Pourquoi

Sur un serveur Linux, presque tout ce qui compte est du texte. La configuration de Signalements est un fichier texte dans /etc/signalements/. Les journaux de l'application, de Nginx, de PostgreSQL, sont du texte. La liste des utilisateurs (/etc/passwd), la table des systèmes de fichiers à monter (/etc/fstab), les dépôts de paquets : du texte. C'est un choix de conception hérité d'Unix, et il a une conséquence très pratique : une poignée d'outils suffit pour lire, chercher, résumer et modifier à peu près n'importe quoi sur la machine.

Ce matin, l'équipe vous signale des erreurs 500 sur l'API. Il faut lire le journal d'accès, compter les erreurs, voir si elles viennent d'un client particulier, suivre le journal pendant qu'un collègue rejoue la requête fautive, puis augmenter le nombre de processus de l'application dans son fichier de configuration. Rien de difficile, mais quelques pièges : un fichier de plusieurs gigaoctets qu'il ne faut pas afficher d'un bloc, un journal qui change de fichier en pleine lecture, un éditeur dont on ne sait pas sortir, et un fichier de configuration modifié avec une faute de frappe qui empêche le service de redémarrer.

Les concepts

Afficher, paginer, extraire

Trois familles d'outils, selon ce que l'on veut voir :

BesoinOutilRemarque
Tout le fichier, d'un bloccatSeulement pour les petits fichiers
Parcourir un fichier, chercher dedanslessNe charge pas tout en mémoire, convient aux très gros fichiers
Le début ou la finhead, tailtail -f et tail -F suivent ce qui s'ajoute

cat (concatenate) a été conçu pour mettre bout à bout plusieurs fichiers, et sert surtout à afficher un petit fichier en entier. Pour tout le reste, on utilise un pager (pagineur), un programme qui affiche le texte page par page : less. Son nom est un jeu de mots sur son prédécesseur, more (« less is more »). less lit le fichier au fur et à mesure qu'on avance, ce qui permet d'ouvrir instantanément un journal de 10 Go.

Les filtres

Un filtre est un programme qui lit du texte, le transforme et écrit le résultat. On les enchaîne avec le caractère |, le tube, qui envoie la sortie d'un programme à l'entrée du suivant. La leçon 6 explique en détail ce qui se passe ; pour l'instant, retenez que a | b signifie « ce que a affiche, b le lit ». Les filtres de base :

  • wc (word count) compte lignes, mots et octets ;
  • sort trie les lignes ;
  • uniq fusionne les lignes identiques consécutives (d'où le sort qui le précède presque toujours) ;
  • cut extrait des colonnes ;
  • grep ne garde que les lignes qui contiennent un motif.

Ces outils sont l'objet du cours Traiter du texte : grep, sed, awk, jq. Cette leçon donne de quoi lire un journal.

Ce qu'est un fichier texte, vraiment

Un fichier texte est une suite d'octets, que l'on interprète comme des caractères selon un encodage. Deux conventions doivent coïncider entre celui qui écrit et celui qui lit :

  • L'encodage des caractères. Les systèmes Linux modernes utilisent UTF-8, dans lequel les caractères accentués occupent deux octets. Un fichier produit par un vieux logiciel Windows peut être en ISO-8859-1 (Latin-1) ou en Windows-1252, où é tient en un seul octet. Lu en UTF-8, cet octet n'a pas de sens, et l'on voit un caractère de remplacement �.
  • La fin de ligne. Unix termine chaque ligne par un seul caractère, le saut de ligne (line feed, \n). Windows utilise deux caractères, retour chariot puis saut de ligne (\r\n, CRLF). Un fichier écrit sous Windows et copié tel quel sur un serveur garde ses \r, invisibles à l'écran, mais bien présents pour les programmes.

Éditer : deux éditeurs à connaître

Sur un serveur, pas d'interface graphique : on édite dans le terminal. Deux éditeurs sont présents presque partout :

  • nano : simple, les raccourcis sont affichés en bas de l'écran. C'est l'éditeur par défaut d'Ubuntu et de Debian.
  • vim (Vi IMproved), descendant de vi, l'éditeur historique d'Unix, normalisé par POSIX, qu'on trouve même sur les systèmes les plus dépouillés. Il est modal : les touches n'ont pas le même effet selon le mode, ce qui le rend très efficace une fois appris, et déroutant au premier contact.

Vous n'avez pas besoin de maîtriser vim. Vous avez besoin de savoir en sortir, et de faire une modification simple quand il est le seul disponible.

En pratique

Les sorties de cette leçon ont été produites sur Ubuntu 24.04 avec LC_ALL=C.UTF-8. Le journal d'accès de Signalements utilisé ici est un fichier d'exemple : créez-le pour obtenir exactement les mêmes résultats. La syntaxe <<'EOF' (un here-document, qui donne à cat le texte qui suit jusqu'à la ligne EOF) est expliquée à la leçon 6.

$ mkdir -p ~/essais && cd ~/essais
$ cat > acces.log <<'EOF'
2026-10-05T08:12:03 10.0.0.12 GET /signalements 200 12ms
2026-10-05T08:12:04 10.0.0.15 POST /signalements 201 35ms
2026-10-05T08:13:10 10.0.0.12 GET /sante 200 2ms
2026-10-05T09:01:44 10.0.0.31 GET /signalements/42 404 3ms
2026-10-05T09:02:01 10.0.0.15 POST /signalements 500 120ms
2026-10-05T09:02:09 10.0.0.15 POST /signalements 500 118ms
2026-10-05T09:15:30 10.0.0.12 GET /sante 200 2ms
2026-10-05T10:20:00 10.0.0.44 GET /signalements 200 15ms
EOF

Chaque ligne contient, séparés par des espaces : la date et l'heure, l'adresse du client, la méthode HTTP, le chemin, le code de réponse et la durée.

Mesurer avant d'afficher

Avant d'ouvrir un fichier inconnu, regardez sa taille. Un cat sur un journal de 5 Go noie le terminal pendant de longues minutes.

$ ls -lh acces.log
$ wc -l acces.log
8 acces.log

wc -l compte les lignes (-w les mots, -c les octets). Sur un vrai serveur, ls -lh /var/log/nginx/ ou du -h (leçon 4) donnent l'ordre de grandeur.

Le début, la fin

$ head -n 2 acces.log
2026-10-05T08:12:03 10.0.0.12 GET /signalements 200 12ms
2026-10-05T08:12:04 10.0.0.15 POST /signalements 201 35ms
$ tail -n 1 acces.log
2026-10-05T10:20:00 10.0.0.44 GET /signalements 200 15ms

head affiche les premières lignes, tail les dernières, dix par défaut, -n pour un autre nombre. Pour un journal, c'est la fin qui intéresse : les événements les plus récents y sont.

Parcourir avec less

$ less acces.log
$ less -S -N /var/log/syslog

Une fois dans less, les commandes tiennent en quelques touches :

ToucheEffet
Espace, bPage suivante, page précédente
g, GDébut, fin du fichier
/motifChercher vers l'avant (?motif vers l'arrière)
n, NOccurrence suivante, précédente
FSuivre la fin du fichier comme tail -f ; Ctrl+C pour arrêter de suivre
vOuvrir le fichier dans l'éditeur (VISUAL, sinon EDITOR, sinon vi)
qQuitter

Les options -S (couper les lignes trop longues au lieu de les replier) et -N (numéroter les lignes) rendent les journaux bien plus lisibles. Le motif de recherche est une expression régulière : / 50[0-9] trouve toutes les erreurs 5xx.

Beaucoup de commandes utilisent less sans qu'on le demande : man, git log, journalctl (leçon 11). Les mêmes touches y fonctionnent.

Suivre un journal : tail -f et tail -F

tail -f affiche la fin du fichier, puis reste ouvert et affiche chaque nouvelle ligne au moment où elle est écrite. C'est l'outil du diagnostic en direct : un collègue rejoue la requête, vous voyez la ligne apparaître.

Il y a un piège, et il se produit chaque nuit sur les serveurs : la rotation des journaux. Pour éviter qu'un journal ne grossisse indéfiniment, logrotate renomme régulièrement app.log en app.log.1 et fait créer un nouveau app.log. Que devient un tail -f en cours ? Reproduisons-le. On lance les deux variantes en arrière-plan pendant huit secondes, chacune écrivant ce qu'elle voit dans un fichier, puis on simule une rotation :

$ echo "ligne 1" > app.log
$ timeout 8 tail -f app.log > sortie-f.txt &
$ timeout 8 tail -F app.log > sortie-F.txt 2>&1 &
$ mv app.log app.log.1
$ echo "ligne 2 (ancien fichier)" >> app.log.1
$ echo "ligne 3 (nouveau fichier)" > app.log
$ sleep 8
$ cat sortie-f.txt
ligne 1
ligne 2 (ancien fichier)
$ cat sortie-F.txt
ligne 1
ligne 2 (ancien fichier)
tail: 'app.log' has been replaced;  following new file
ligne 3 (nouveau fichier)

tail -f a continué de lire l'ancien fichier, renommé en app.log.1, et n'a jamais vu la ligne 3 : il suit un fichier ouvert, c'est-à-dire un inode (leçon 4), pas un nom. tail -F suit le nom : il a remarqué que app.log désignait désormais un autre fichier, l'a signalé, et a basculé. L'aide de tail le dit : -F équivaut à --follow=name --retry, et --retry lui fait aussi attendre un fichier qui n'existe pas encore. Pour un journal, utilisez tail -F.

Résumer un journal

Combien de réponses de chaque code ? On extrait la cinquième colonne, on trie, on compte les lignes identiques, et l'on trie le résultat par nombre décroissant :

$ cut -d' ' -f5 acces.log | sort | uniq -c | sort -rn
      4 200
      2 500
      1 404
      1 201
  • cut -d' ' -f5 : couper chaque ligne sur le délimiteur espace (-d) et garder le cinquième champ (-f). -f2,5 garderait deux champs, -c1-13 les caractères 1 à 13.
  • sort : trier, pour que les valeurs identiques se suivent.
  • uniq -c : fusionner les lignes identiques consécutives, en préfixant le nombre d'occurrences.
  • sort -rn : trier numériquement (-n), à l'envers (-r).

Pourquoi le premier sort est-il indispensable ? Parce que uniq ne compare une ligne qu'à la précédente :

$ cut -d' ' -f2 acces.log | uniq -c
      1 10.0.0.12
      1 10.0.0.15
      1 10.0.0.12
      1 10.0.0.31
      2 10.0.0.15
      1 10.0.0.12
      1 10.0.0.44

10.0.0.12 apparaît trois fois, en trois lignes séparées. La liste des clients distincts, elle, s'obtient directement avec sort -u :

$ cut -d' ' -f2 acces.log | sort -u
10.0.0.12
10.0.0.15
10.0.0.31
10.0.0.44

Chercher avec grep

$ grep -c ' 500 ' acces.log
2
$ grep -n 'POST' acces.log
2:2026-10-05T08:12:04 10.0.0.15 POST /signalements 201 35ms
5:2026-10-05T09:02:01 10.0.0.15 POST /signalements 500 120ms
6:2026-10-05T09:02:09 10.0.0.15 POST /signalements 500 118ms
$ grep -v '/sante' acces.log | wc -l
6
$ grep -E ' (404|500) ' acces.log
2026-10-05T09:01:44 10.0.0.31 GET /signalements/42 404 3ms
2026-10-05T09:02:01 10.0.0.15 POST /signalements 500 120ms
2026-10-05T09:02:09 10.0.0.15 POST /signalements 500 118ms
  • -c compte les lignes au lieu de les afficher. Les espaces autour de 500 évitent de compter une durée de 500ms ou un identifiant /signalements/1500.
  • -n préfixe chaque ligne de son numéro, utile pour la retrouver ensuite dans less ou dans l'éditeur.
  • -v inverse : ne garder que les lignes qui ne contiennent pas le motif. Ici, on retire les appels de supervision à /sante, qui encombrent tous les journaux d'accès.
  • -E active les expressions régulières étendues, où (404|500) signifie « 404 ou 500 ».
  • -i ignore la casse ; -r cherche récursivement dans un répertoire (grep -rn 'DATABASE_URL' /etc/signalements/).

Les deux erreurs 500 viennent du même client, 10.0.0.15, sur un POST, à huit secondes d'intervalle : c'est une piste. Le cours Expressions régulières et le cours Traiter du texte vont beaucoup plus loin ; ces cinq options couvrent l'essentiel du diagnostic quotidien.

Comparer deux versions : diff -u

Avant de modifier la configuration, on en fait une copie datée (leçon 4). Après la modification, diff montre exactement ce qui a changé :

$ printf 'port = 8000\nworkers = 2\nlog_level = info\n' > app.conf
$ cp -a app.conf app.conf.2026-10-05
$ # ... modification : workers passe à 4, ajout d'un délai d'expiration ...
$ diff -u app.conf.2026-10-05 app.conf
--- app.conf.2026-10-05	2026-10-05 11:10:59.898874255 +0200
+++ app.conf	2026-10-05 11:10:59.903485524 +0200
@@ -1,3 +1,4 @@
 port = 8000
-workers = 2
+workers = 4
 log_level = info
+timeout = 30
$ echo $?
1

C'est le format unifié, celui des correctifs, de git diff et des demandes de fusion. Il se lit ainsi :

  • les deux premières lignes nomment l'ancien fichier (---) et le nouveau (+++) ;
  • @@ -1,3 +1,4 @@ annonce un bloc : dans l'ancien fichier, 3 lignes à partir de la ligne 1 ; dans le nouveau, 4 lignes à partir de la ligne 1 ;
  • une ligne qui commence par une espace est inchangée (le contexte), - a été retirée, + a été ajoutée. Une ligne modifiée apparaît comme un retrait suivi d'un ajout.

Le code de sortie de diff est utile dans les scripts : 0 si les fichiers sont identiques, 1 s'ils diffèrent, 2 en cas d'erreur. Pour savoir seulement si deux fichiers diffèrent, diff -q.

Reconnaître un problème de fin de ligne

Un collègue a écrit un petit script sous Windows et l'a copié sur le serveur. Il refuse de s'exécuter :

$ ./script-windows.sh
bash: ./script-windows.sh: cannot execute: required file not found

Le message est déroutant, puisque le fichier est là. La commande file, qui devine la nature d'un fichier d'après son contenu, donne la clé :

$ file script-windows.sh
script-windows.sh: Bourne-Again shell script, ASCII text executable, with CRLF line terminators
$ cat -A script-windows.sh
#!/bin/bash^M$
echo bonjour^M$

cat -A rend visibles les caractères invisibles : ^M est le retour chariot \r, $ la fin de ligne. La première ligne, qui indique au noyau quel interpréteur lancer (le shebang, leçon 7), désigne donc un programme nommé /bin/bash\r, qui n'existe pas. Le noyau refuse l'exécution, et Bash 5.2 traduit cette erreur par required file not found ; d'autres versions de Bash et d'autres outils l'affichent sous la forme /bin/bash^M: bad interpreter: No such file or directory. Même lancé explicitement par bash script.sh, un fichier en CRLF produit des erreurs, sur chaque commande :

$ printf 'cd /opt\r\nls\r\n' > s2.sh
$ bash s2.sh
s2.sh: line 1: cd: $'/opt\r': No such file or directory
s2.sh: line 2: $'ls\r': command not found

Bash affiche le nom fautif sous la forme $'...', qui rend le \r visible : c'est la signature d'un fichier Windows. Correction : retirer les \r.

$ tr -d '\r' < script-windows.sh > script-unix.sh
$ chmod +x script-unix.sh && ./script-unix.sh
bonjour

L'outil dos2unix, à installer, fait la même chose sur place. Mieux vaut régler le problème à la source : configurer l'éditeur du poste Windows en fins de ligne LF, ou Git (core.autocrlf, ou un fichier .gitattributes) pour qu'il ne convertisse pas les scripts.

Reconnaître un problème d'encodage

Un service municipal envoie un export CSV des signalements, produit par un vieux logiciel :

$ file export.csv
export.csv: ISO-8859 text
$ cat export.csv
lieu;description
Rue de la Gare;caf� ferm�
$ iconv -f ISO-8859-1 -t UTF-8 export.csv > export-utf8.csv
$ file export-utf8.csv
export-utf8.csv: Unicode text, UTF-8 text
$ cat export-utf8.csv
lieu;description
Rue de la Gare;café fermé

file reconnaît l'encodage ISO-8859 ; le terminal, en UTF-8, affiche � à la place des octets qu'il ne sait pas décoder. iconv convertit d'un encodage (-f, from) à l'autre (-t, to). Le phénomène inverse existe aussi : un texte UTF-8 lu comme du Latin-1 donne café. Si vous voyez é ou è dans une page web ou une base, c'est presque toujours de l'UTF-8 interprété comme du Latin-1.

Survivre dans nano

$ nano app.conf

nano s'ouvre directement en saisie : vous tapez, le texte s'insère. Les raccourcis sont rappelés en bas de l'écran, où ^ signifie la touche Ctrl et M- la touche Alt :

RaccourciAction
^O puis EntréeEnregistrer (Write Out) ; ^S enregistre sans demander le nom
^XQuitter (nano propose d'enregistrer si le fichier a changé)
^WChercher (Where Is)
^K, ^UCouper la ligne, coller
M-UAnnuler la dernière action
^GAide

Deux options utiles pour éditer de la configuration : nano -l affiche les numéros de ligne, et nano +12 app.conf ouvre directement à la ligne 12, celle que grep -n vous a indiquée.

Survivre dans vim

Il arrivera qu'une commande vous dépose dans vim sans que vous l'ayez demandé : un git commit sans message, un crontab -e, un visudo sur une machine où nano n'est pas installé. Ubuntu fournit d'ailleurs une version réduite de vim (vim.tiny) derrière la commande vi.

vim démarre en mode normal : les touches sont des commandes, pas du texte. Taper dd ne tape pas « dd », cela supprime une ligne. Le minimum vital :

ToucheEffet
ÉchapRevenir au mode normal (en cas de doute, appuyez deux fois)
iPasser en mode insertion, avant le curseur : on tape du texte
/motif puis EntréeChercher ; n pour l'occurrence suivante
x, ddSupprimer un caractère, une ligne
uAnnuler
:wEnregistrer
:wqEnregistrer et quitter ; :x (ou ZZ) enregistre seulement s'il y a eu des changements
:q!Quitter sans enregistrer, en abandonnant les modifications

Les commandes qui commencent par : se tapent en mode normal ; elles s'affichent en bas de l'écran, et se valident par Entrée. La séquence de sortie d'urgence est donc : Échap, :q!, Entrée. Une modification simple : /workers Entrée pour aller à la ligne, i pour insérer, corriger, Échap, :wq Entrée. Pour aller plus loin, la commande vimtutor, fournie avec vim (paquet vim, plus complet que vim.tiny), propose une leçon interactive d'une demi-heure.

Choisir son éditeur

Les programmes qui ouvrent un éditeur (crontab -e, git commit, sudoedit, la touche v de less) consultent les variables d'environnement VISUAL, puis EDITOR. À défaut, Debian et Ubuntu utilisent la commande editor, qui désigne l'éditeur choisi pour le système à travers une chaîne de liens symboliques :

$ ls -l /usr/bin/editor /etc/alternatives/editor
lrwxrwxrwx 1 root root  9 Feb 10  2026 /etc/alternatives/editor -> /bin/nano
lrwxrwxrwx 1 root root 24 Mar 31  2024 /usr/bin/editor -> /etc/alternatives/editor

Pour imposer votre éditeur, ajoutez export EDITOR=nano (ou vim) à votre fichier ~/.bashrc : la leçon 7 explique ce fichier et ce que fait export.

Modifier une configuration système en sécurité

Le fichier /etc/signalements/app.conf appartient à root et n'est lisible que par lui et le groupe du service. La procédure complète, que vous appliquerez à chaque modification de configuration :

$ sudo cp -a /etc/signalements/app.conf /etc/signalements/app.conf.$(date +%F)
$ sudoedit /etc/signalements/app.conf
$ sudo diff -u /etc/signalements/app.conf.$(date +%F) /etc/signalements/app.conf
$ sudo systemctl restart signalements
$ systemctl status signalements
$ curl -s http://127.0.0.1:8000/sante
  1. Sauvegarder l'original, avec ses attributs (leçon 4).
  2. Éditer avec sudoedit (équivalent de sudo -e), et non sudo nano ou sudo vim. Le manuel de sudo décrit son fonctionnement : il fait une copie temporaire du fichier, qui vous appartient ; il lance l'éditeur en tant que vous, pas en root ; puis, si la copie a été modifiée, il la recopie à l'emplacement d'origine. L'éditeur est choisi par les variables SUDO_EDITOR, VISUAL puis EDITOR.
  3. Relire le changement avec diff -u : on doit voir exactement la modification voulue, et rien d'autre.
  4. Valider quand le logiciel le permet. Beaucoup de services ont une commande de vérification de configuration (nginx -t, sshd -t, visudo -c) : lancez-la avant de redémarrer, parce qu'un service qui refuse sa configuration au redémarrage est un service arrêté.
  5. Redémarrer et vérifier que le service fonctionne (leçon 11), puis que l'application répond.

Si quelque chose ne va pas, la copie datée permet de revenir en arrière en une commande.

Sous le capot

Pourquoi less ouvre un fichier de 10 Go instantanément. Un éditeur classique charge tout le fichier en mémoire avant de l'afficher. less ne lit que ce qu'il doit montrer, plus un peu d'avance, et se déplace dans le fichier par lecture à une position donnée. Seuls certains gestes l'obligent à tout parcourir, comme aller à la fin (G) d'un très gros fichier avec les numéros de ligne affichés, que less doit alors compter. C'est pour cela qu'on peut, et qu'on doit, préférer less à un éditeur pour lire un gros journal : ouvrir un fichier de plusieurs gigaoctets dans nano ou vim peut épuiser la mémoire du serveur.

Comment tail -f sait qu'il y a du nouveau. GNU tail utilise, quand il le peut, le mécanisme inotify du noyau, qui le prévient des modifications du fichier ; sinon, il interroge le fichier à intervalle régulier (une seconde par défaut, réglable avec -s). En mode -f (--follow=descriptor), il garde le descripteur du fichier ouvert : après un renommage, ce descripteur désigne toujours le même inode, d'où la lecture de l'ancien fichier. En mode -F (--follow=name), il vérifie aussi régulièrement que le nom désigne toujours le même inode, et rouvre le fichier sinon.

Ce que fait vraiment le noyau avec un #!. Quand on exécute un fichier, le noyau (appel système execve(2)) regarde ses premiers octets. S'ils commencent par #!, le reste de la ligne, jusqu'au saut de ligne, est le chemin de l'interpréteur, suivi d'un argument facultatif. Le \r d'un fichier Windows fait donc partie du chemin : execve échoue avec l'erreur ENOENT (« fichier introuvable »), qui concerne l'interpréteur et non le script, d'où un message qui semble absurde.

Pourquoi sudoedit est plus sûr. Un éditeur est un programme très puissant : il ouvre et enregistre n'importe quel fichier, lance des commandes (:!commande dans vim), charge des greffons et des fichiers de configuration. Lancé par sudo vim, tout cela s'exécute en root. Une règle sudo qui autorise seulement « éditer ce fichier » avec sudo vim /etc/signalements/app.conf donne en réalité un shell root à quiconque sait taper :!bash. Avec sudoedit, l'éditeur tourne avec vos droits ; seule la recopie finale, faite par sudo lui-même, est privilégiée. less a un risque comparable (sa commande ! lance un shell) : c'est pour cela qu'il propose un mode sécurisé, activé par la variable LESSSECURE=1, qui désactive ces fonctions.

Pièges courants

cat sur un fichier énorme ou binaire. Le terminal est inondé, ou se met à afficher des caractères étranges parce que des octets binaires ont été interprétés comme des séquences de contrôle. Ctrl+C arrête l'affichage ; la commande reset remet le terminal en état. Mesurez d'abord (ls -lh, wc -l), utilisez less ou head.

tail -f qui « s'arrête » au milieu de la nuit. C'est la rotation : vous suivez l'ancien fichier. Utilisez tail -F.

uniq sans sort. Il ne fusionne que les lignes consécutives : les comptes sont faux sans tri préalable.

cut sur des colonnes séparées par plusieurs espaces. cut -d' ' considère chaque espace comme un séparateur : deux espaces consécutives délimitent un champ vide, et les numéros de colonnes se décalent. C'est le cas de la sortie de ls -l ou de ps. On utilise alors awk '{print $5}', qui traite les suites d'espaces comme un seul séparateur (cours Traiter du texte).

grep qui en trouve trop. grep 500 trouve aussi 1500, 500ms et 5000. Encadrez le motif (espaces, -w pour un mot entier) ou utilisez une expression plus précise.

Coincé dans vim. Échap, :q!, Entrée. Si l'écran affiche E37: No write since last change (add ! to override), vous avez tapé :q sans le ! alors que le fichier a été modifié.

Le fichier .swp. vim enregistre pendant l'édition un fichier d'échange .app.conf.swp. Si une session est interrompue (connexion SSH coupée), vim le signale à la prochaine ouverture avec un message ATTENTION et propose de récupérer les modifications. Lisez le message, récupérez ou supprimez le fichier d'échange, mais ne l'ignorez pas : c'est peut-être qu'un collègue est en train d'éditer le même fichier.

Éditer sans sauvegarde, redémarrer sans valider. Une faute de frappe dans un fichier de configuration se découvre au redémarrage, quand le service refuse de démarrer. La procédure en cinq étapes existe pour cela.

Sécurité

  • sudoedit plutôt que sudo nano ou sudo vim, pour ne pas exécuter un éditeur, ses greffons et ses commandes en root. Dans une règle sudo qui délègue l'édition d'un fichier, utilisez toujours sudoedit.
  • Ce qui s'affiche se voit. Un cat sur un fichier qui contient un mot de passe (DATABASE_URL, une clé d'API) l'affiche à l'écran, dans un partage d'écran, dans l'historique de défilement du terminal, et peut-être dans l'enregistrement d'une réunion. Pour vérifier qu'une variable est présente, cherchez le nom sans afficher la valeur : sudo grep -c '^DATABASE_URL=' /etc/signalements/env. Et ne copiez jamais un fichier de configuration complet dans un ticket ou une discussion.
  • Les copies de travail des éditeurs contiennent les mêmes secrets. Fichiers d'échange de vim, copies de sauvegarde app.conf~ de certains éditeurs, copies datées : vérifiez qu'ils gardent les droits restreints de l'original, et supprimez ceux qui ne servent plus.
  • Les journaux sont des données. Un journal d'accès contient des adresses IP, parfois des identifiants dans les URL, des adresses électroniques, des données personnelles au sens du RGPD. Ils ne s'exportent pas, ne se copient pas sur un poste personnel et ne s'envoient pas sans raison et sans précaution.

En production

  • On ne lit pas les journaux d'un parc de serveurs un par un. À l'échelle, les journaux sont centralisés et interrogés dans un outil dédié (cours Journaux centralisés avec Loki). Les commandes de cette leçon restent celles du diagnostic sur une machine, et celles qui permettent de comprendre ce que font les outils centralisés.
  • On ne modifie pas une configuration à la main sur un serveur géré. Si le fichier est déployé par un outil (Ansible, cloud-init, un paquet, une image), une modification manuelle sera écrasée au prochain déploiement, ou créera une dérive entre ce qui est décrit et ce qui tourne. La modification manuelle se fait en urgence, se note, et se reporte immédiatement dans l'outil.
  • Lisez la configuration effective, pas seulement le fichier. Beaucoup de logiciels assemblent plusieurs fichiers (/etc/ssh/sshd_config puis sshd_config.d/*.conf) ; leur commande de vérification affiche souvent la configuration finale (sshd -T, nginx -T).
  • Chez Lyneko, la configuration des applications vit dans Git et arrive dans le cluster par Argo CD (cours GitOps avec Argo CD) : diff -u y prend la forme de la relecture d'une demande de fusion. Les réflexes de cette leçon restent ceux qu'on applique sur toute machine où l'on intervient directement.

Exercices

1. Le client bavard (niveau 100). À partir du fichier acces.log de la leçon, écrivez la commande qui affiche les adresses des clients classées par nombre de requêtes décroissant, en excluant les appels à /sante.

Solution
$ grep -v ' /sante ' acces.log | cut -d' ' -f2 | sort | uniq -c | sort -rn
      3 10.0.0.15
      1 10.0.0.44
      1 10.0.0.31
      1 10.0.0.12

grep -v retire les appels de supervision, cut extrait l'adresse, sort | uniq -c compte, sort -rn classe. Sans le premier grep, 10.0.0.12 arriverait à égalité avec 10.0.0.15, avec trois requêtes dont deux de supervision. Remarquez l'ordre des ex aequo : -r inverse le tri de la ligne entière, d'où les adresses à une requête en ordre décroissant.

2. Le script qui ne démarre pas (niveau 100). Un script deploie.sh, récupéré depuis le poste Windows d'un collègue, affiche cannot execute: required file not found alors que ls -l le montre bien présent et exécutable. Donnez deux commandes pour confirmer le diagnostic, et une pour le corriger.

Solution

file deploie.sh signale with CRLF line terminators, et cat -A deploie.sh | head -1 montre #!/bin/bash^M$. Correction : tr -d '\r' < deploie.sh > deploie.tmp && mv deploie.tmp deploie.sh && chmod +x deploie.sh (ou dos2unix deploie.sh si l'outil est installé). Le mv remplace le fichier en une opération, mais crée un nouvel inode : il faut remettre le droit d'exécution. Puis régler la source (éditeur ou .gitattributes) pour que cela ne se reproduise pas.

3. Sortir de vim (niveau 100). Ouvrez app.conf avec vi. Sans regarder la leçon : (a) cherchez la ligne workers, (b) remplacez 2 par 3, (c) quittez sans enregistrer, (d) rouvrez, refaites la modification et enregistrez. Vérifiez avec diff -u par rapport à votre copie datée.

Solution

(a) /workers puis Entrée. (b) Placez le curseur sur le 2 (flèches, ou $ pour la fin de ligne), x pour le supprimer, i pour passer en insertion, tapez 3, Échap. Variante plus rapide : r3 remplace le caractère sous le curseur. (c) :q! Entrée. (d) Même chose, puis :wq Entrée. diff -u app.conf.2026-10-05 app.conf montre -workers = 2 et +workers = 3.

4. La délégation dangereuse (niveau 100). Un administrateur veut permettre à l'équipe de développement de modifier /etc/signalements/app.conf, et propose de l'autoriser à lancer sudo vim /etc/signalements/app.conf. Expliquez le problème et proposez mieux.

Solution

vim lancé par sudo tourne en root. Depuis vim, :!bash ouvre un shell root, et :e /etc/shadow ouvre n'importe quel fichier : la règle donne en réalité tous les droits sur la machine. Mieux : autoriser sudoedit /etc/signalements/app.conf, qui fait éditer une copie avec les droits de l'utilisateur et ne fait en root que la recopie de ce seul fichier. Encore mieux, à terme : gérer ce fichier dans Git et le déployer par un outil, pour que chaque modification soit relue (leçon 8 pour la délégation par sudo).

Récapitulatif

  • Mesurer avant d'afficher (ls -lh, wc -l). cat pour les petits fichiers, less pour tout le reste (/ chercher, F suivre, q quitter), head et tail pour les extrémités.
  • tail -F, et non -f, pour suivre un journal : il survit à la rotation.
  • cut | sort | uniq -c | sort -rn résume une colonne ; uniq exige un sort préalable ; grep -c, -n, -v, -i, -E, -r couvrent l'essentiel de la recherche.
  • diff -u montre un changement au format unifié : - retiré, + ajouté, espace pour le contexte.
  • file révèle les fins de ligne CRLF (le ^M de cat -A, le $'...\r' des messages de Bash) et les encodages ; tr -d '\r' et iconv corrigent.
  • nano : ^O enregistrer, ^X quitter, ^W chercher. vim : i insérer, Échap, :wq enregistrer et quitter, :q! quitter sans enregistrer.
  • Une configuration système se modifie en cinq temps : copie datée, sudoedit, diff -u, validation, redémarrage vérifié.

Pour aller plus loin

  • La page de manuel de less (man less), en particulier la liste des commandes et la section SECURITY.
  • Le manuel de GNU Diffutils, chapitre sur le format unifié, et celui de GNU Grep pour la liste complète des options.
  • vimtutor, une demi-heure pour ne plus jamais être coincé dans vim, et l'aide en ligne de vim (:help).
  • La leçon suivante, qui explique ce que fait réellement le | utilisé tout au long de celle-ci, et comment rediriger la sortie et les erreurs d'une commande.
Voir ma constellation →

Sources