Lire et chercher#

Hide code cell source

import matplotlib.pyplot as plt
import matplotlib.patches as patches
import numpy as np
import seaborn as sns

sns.set_theme(style="whitegrid", palette="muted", font_scale=1.1)

Lire des fichiers#

Linux offre plusieurs outils pour lire le contenu des fichiers, adaptés à des contextes différents : affichage intégral, lecture paginée, consultation des premières ou dernières lignes, ou surveillance en temps réel.

cat — concaténer et afficher#

cat (concatenate) est le plus direct : il lit le contenu d’un ou plusieurs fichiers et l’écrit sur la sortie standard. Son nom vient de sa capacité à concaténer plusieurs fichiers.

# Afficher le contenu d'un fichier
cat fichier.txt

# Afficher plusieurs fichiers successivement
cat fichier1.txt fichier2.txt fichier3.txt

# Concaténer plusieurs fichiers dans un nouveau fichier
cat partie1.txt partie2.txt partie3.txt > complet.txt

# -n : numéroter toutes les lignes
cat -n fichier.txt

# -b : numéroter seulement les lignes non vides
cat -b fichier.txt

# -A : afficher les caractères non imprimables
# (^ pour les caractères de contrôle, $ en fin de ligne)
cat -A fichier.txt

# -s : compresser les lignes vides consécutives en une seule
cat -s fichier.txt

# Lecture depuis l'entrée standard (terminer avec Ctrl+D)
cat > nouveau_fichier.txt
# Tout ce que vous tapez sera écrit dans le fichier
# Ctrl+D pour terminer

Remarque 12

L’usage de cat fichier | commande est souvent appelé UUOC (Useless Use Of Cat) par les puristes Unix, car la plupart des commandes acceptent directement un nom de fichier : grep motif fichier est équivalent à cat fichier | grep motif. Cependant, cat reste utile pour la concaténation, la création de fichiers et la lisibilité dans les scripts complexes.

less — lecture paginée#

less est le pagineur de référence sous Linux. Contrairement à cat, il n’affiche pas tout le fichier d’un coup mais présente une page à la fois, permettant de naviguer librement dans le fichier. Son nom est un jeu de mots : less is more (allusion au pagineur more qu’il remplace avantageusement).

# Ouvrir un fichier avec less
less fichier.txt
less /var/log/syslog

# Navigation dans less :
# Espace ou f      : page suivante
# b                : page précédente
# Entrée ou ↓      : ligne suivante
# ↑                : ligne précédente
# g ou <           : aller au début du fichier
# G ou >           : aller à la fin du fichier
# /motif           : rechercher en avant
# ?motif           : rechercher en arrière
# n                : occurrence suivante
# N                : occurrence précédente
# q                : quitter

# Ouvrir plusieurs fichiers
less fichier1.txt fichier2.txt
# :n passe au fichier suivant, :p revient au précédent

# -N : afficher les numéros de ligne
less -N fichier.txt

# -i : recherche insensible à la casse
less -i fichier.txt

# -S : ne pas couper les longues lignes (défilement horizontal)
less -S fichier.csv

# +G : ouvrir directement à la fin du fichier
less +G /var/log/auth.log

# +/motif : ouvrir et chercher immédiatement
less +/ERROR /var/log/syslog

Définition 15 (less vs more vs most)

  • more : pagineur historique (1978), simple. Il ne permet que d’avancer dans le fichier (pas de retour en arrière). Encore présent sur tous les systèmes pour la compatibilité.

  • less : pagineur avancé (1983, Mark Nudelman), navigation bidirectionnelle, recherche, support des couleurs ANSI, plus rapide que more sur les grands fichiers (ne charge pas tout le fichier en mémoire). C’est le pagineur par défaut de man.

  • most : pagineur alternatif avec défilement horizontal et fenêtres multiples. Moins courant mais utile pour les fichiers avec de longues lignes.

head — afficher le début d’un fichier#

# Afficher les 10 premières lignes (par défaut)
head fichier.txt

# -n : spécifier le nombre de lignes
head -n 20 fichier.txt
head -20 fichier.txt    # raccourci équivalent

# -c : afficher les N premiers octets
head -c 100 fichier.txt
head -c 1K fichier.txt
head -c 1M fichier.bin

# Afficher les N premières lignes de plusieurs fichiers
head -n 5 fichier1.txt fichier2.txt fichier3.txt

# Tout sauf les N dernières lignes (syntaxe GNU)
head -n -5 fichier.txt    # tout sauf les 5 dernières lignes

tail — afficher la fin d’un fichier#

tail est particulièrement précieux pour surveiller les fichiers de log en temps réel.

# Afficher les 10 dernières lignes (par défaut)
tail fichier.txt

# -n : spécifier le nombre de lignes
tail -n 20 fichier.txt
tail -20 fichier.txt

# -c : afficher les N derniers octets
tail -c 500 fichier.txt

# À partir de la N-ème ligne
tail -n +10 fichier.txt   # à partir de la ligne 10 (incluse)

# -f : suivre le fichier en temps réel (follow)
# S'arrête avec Ctrl+C
tail -f /var/log/nginx/access.log

# -F : comme -f, mais gère la rotation des logs
# (suit le fichier même si nginx renomme et recrée le fichier)
tail -F /var/log/nginx/access.log

# Suivre plusieurs fichiers simultanément
tail -f /var/log/nginx/access.log /var/log/nginx/error.log

# Combiner head et tail pour extraire des lignes spécifiques
# Afficher les lignes 15 à 25 d'un fichier
head -n 25 fichier.txt | tail -n 11

Exemple 13 (Surveillance des logs en temps réel)

# Surveiller les connexions SSH
tail -F /var/log/auth.log | grep "sshd"

# Surveiller les erreurs nginx en temps réel
tail -F /var/log/nginx/error.log

# Surveiller un log et filtrer en temps réel avec grep
tail -f /var/log/syslog | grep -i "error\|warning\|critical"

# Surveiller plusieurs logs avec des couleurs différentes (multitail)
# sudo apt install multitail
multitail /var/log/nginx/access.log /var/log/nginx/error.log

### wc — compter

`wc` (*word count*) compte les lignes, mots et octets d'un fichier.

```bash
# Compter lignes, mots et octets
wc fichier.txt
# Sortie : "  142   1205  8342 fichier.txt"
#           lignes  mots  octets

# -l : compter uniquement les lignes
wc -l fichier.txt
wc -l /etc/passwd           # nombre d'utilisateurs

# -w : compter uniquement les mots
wc -w fichier.txt

# -c : compter uniquement les octets
wc -c fichier.txt

# -m : compter les caractères (utile avec UTF-8)
wc -m fichier.txt

# Compter plusieurs fichiers et afficher un total
wc -l fichier1.txt fichier2.txt fichier3.txt

# Compter les fichiers dans un répertoire
ls /etc | wc -l

# Compter les lignes de code Python dans un projet
find . -name "*.py" | xargs wc -l | tail -1

grep — chercher dans le contenu#

grep (Global Regular Expression Print) est l’outil de recherche textuelle le plus puissant et le plus utilisé de Linux. Il parcourt un ou plusieurs fichiers ligne par ligne et affiche les lignes qui correspondent à un motif de recherche.

Définition 16 (grep)

grep lit l’entrée ligne par ligne et affiche les lignes correspondant à un motif (pattern). Ce motif est par défaut une expression régulière de base (BRE — Basic Regular Expression). La syntaxe générale est :

grep [options] motif [fichier(s)]

Si aucun fichier n’est spécifié, grep lit depuis l’entrée standard, ce qui permet de l’utiliser dans des pipelines.


### Options essentielles de grep

```bash
# Recherche de base
grep "erreur" fichier.log

# -i : insensible à la casse
grep -i "erreur" fichier.log
grep -i "Error\|error\|ERREUR" fichier.log

# -r ou -R : récursif (parcourir les sous-répertoires)
grep -r "TODO" /home/alice/projets/
grep -R "mot_de_passe" /etc/

# -n : afficher le numéro de ligne
grep -n "def main" programme.py

# -l : afficher seulement les noms de fichiers qui contiennent le motif
grep -rl "import numpy" /home/alice/

# -L : afficher les noms de fichiers qui NE contiennent PAS le motif
grep -rL "encoding" /etc/*.conf

# -v : inverser la correspondance (lignes ne correspondant PAS)
grep -v "^#" /etc/nginx/nginx.conf    # exclure les commentaires
grep -v "^$" fichier.txt              # exclure les lignes vides

# -c : compter le nombre de lignes correspondantes
grep -c "ERROR" /var/log/syslog

# -E : utiliser les expressions régulières étendues (ERE)
grep -E "erreur|warning|critique" fichier.log

# -F : traiter le motif comme une chaîne fixe (pas de regex)
# Plus rapide quand on ne cherche pas de motif complexe
grep -F "http://exemple.com/page?id=42" access.log

# -o : afficher uniquement la partie correspondante (pas toute la ligne)
grep -o "[0-9]\{1,3\}\(\.[0-9]\{1,3\}\)\{3\}" access.log  # extraire les IPs

# -A n : afficher n lignes Après chaque correspondance
grep -A 3 "CRITICAL" /var/log/syslog

# -B n : afficher n lignes Avant chaque correspondance
grep -B 2 "CRITICAL" /var/log/syslog

# -C n : afficher n lignes de contexte (avant et après)
grep -C 5 "CRITICAL" /var/log/syslog

# --color=auto : colorier les correspondances (activé par défaut avec alias)
grep --color=auto "erreur" fichier.log

# -w : correspondance sur un mot entier (délimité par des séparateurs de mots)
grep -w "int" programme.c    # ne correspond pas à "integer" ou "point"

# -x : correspondance sur une ligne entière
grep -x "root" /etc/group

# -m n : s'arrêter après n correspondances
grep -m 5 "ERROR" /var/log/syslog

# Exclure des répertoires lors d'une recherche récursive
grep -r "motif" . --exclude-dir=".git" --exclude-dir="node_modules"

# Filtrer par extension de fichier
grep -r "motif" . --include="*.py"
grep -r "motif" . --include="*.{py,js,ts}"

Exemple 14 (Pipelines grep courants)

# Trouver les processus qui consomment de la mémoire
ps aux | grep -v "^USER" | sort -k4 -rn | head -10

# Chercher les erreurs dans les logs des dernières 24h
find /var/log -name "*.log" -mtime -1 | xargs grep -l "ERROR"

# Extraire toutes les adresses email d'un fichier
grep -oE "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}" contacts.txt

# Compter les codes de statut HTTP dans les logs nginx
awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn

# Trouver les fichiers Python contenant une classe spécifique
grep -rn "class MonModèle" /home/alice/projet/ --include="*.py"

# Vérifier si un service est actif dans les logs
sudo grep -c "started" /var/log/syslog | tail -1

## Expressions régulières

Les expressions régulières (*regular expressions* ou *regex*) sont un mini-langage pour décrire des motifs de texte. Elles sont utilisées par `grep`, `sed`, `awk`, Python, JavaScript et presque tous les langages de programmation modernes. Comprendre les regex est l'une des compétences les plus rentables en programmation.

### Expressions régulières de base (BRE)

Linux distingue les **BRE** (*Basic Regular Expressions*, utilisées par `grep` sans option) et les **ERE** (*Extended Regular Expressions*, utilisées par `grep -E` ou `egrep`).

```{prf:definition} Métacaractères des expressions régulières
:label: definition-05-03

**Ancres :**
- **`^`** : début de ligne. `^bonjour` correspond à une ligne commençant par « bonjour ».
- **`$`** : fin de ligne. `monde$` correspond à une ligne se terminant par « monde ».
- **`\b`** : limite de mot (*word boundary*). `\bfoo\b` correspond à « foo » mais pas à « foobar ».

**Correspondance de caractères :**
- **`.`** : n'importe quel caractère unique (sauf newline).
- **`[abc]`** : l'un des caractères a, b ou c (classe de caractères).
- **`[^abc]`** : tout caractère sauf a, b, c (classe négative).
- **`[a-z]`** : un caractère entre a et z (intervalle).
- **`[0-9]`** : un chiffre de 0 à 9.
- **`[a-zA-Z0-9_]`** : lettre, chiffre ou underscore.

**Quantificateurs :**
- **`*`** : zéro ou plusieurs répétitions du caractère/groupe précédent.
- **`+`** : une ou plusieurs répétitions (ERE uniquement, ou `\+` en BRE).
- **`?`** : zéro ou une répétition (ERE uniquement, ou `\?` en BRE).
- **`{n}`** : exactement n répétitions.
- **`{n,}`** : n ou plus de répétitions.
- **`{n,m}`** : entre n et m répétitions.

**Groupement et alternatives (ERE) :**
- **`(abc)`** : groupe. Permet d'appliquer un quantificateur à un groupe.
- **`a|b`** : alternative (a ou b).

**Classes POSIX :**
- **`[:alpha:]`** : lettres (`[a-zA-Z]`).
- **`[:digit:]`** : chiffres (`[0-9]`).
- **`[:alnum:]`** : lettres et chiffres.
- **`[:space:]`** : espaces, tabulations, newlines.
- **`[:upper:]`** : lettres majuscules.
- **`[:lower:]`** : lettres minuscules.

Exemple 15 (Expressions régulières en pratique)

# Trouver les lignes vides (début = fin de ligne)
grep "^$" fichier.txt

# Trouver les lignes commençant par un commentaire
grep "^#" /etc/nginx/nginx.conf
grep "^[[:space:]]*#" fichier.py    # aussi celles indentées

# Trouver les lignes contenant une adresse IP (simplifiée)
grep -E "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" access.log

# Trouver les URLs http ou https
grep -E "https?://[^ ]+" fichier.txt

# Trouver les adresses email
grep -E "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}" fichier.txt

# Trouver les lignes avec un nombre de 3 à 5 chiffres
grep -E "\b[0-9]{3,5}\b" données.txt

# Trouver les fonctions Python (def suivi d'un nom)
grep -E "^def [a-zA-Z_][a-zA-Z0-9_]*\(" programme.py

# Trouver les imports Python
grep -E "^(import|from) " programme.py

# Trouver les lignes qui ne contiennent que des espaces
grep "^[[:space:]]*$" fichier.txt

# Mot au début de ligne, avec n'importe quelle fin
grep "^ERROR.*database" /var/log/app.log

### Variantes de grep

Linux fournit plusieurs variantes de `grep` :

- **`grep`** : utilise les BRE par défaut.
- **`grep -E`** ou **`egrep`** : utilise les ERE (*Extended*).
- **`grep -F`** ou **`fgrep`** : correspondance de chaîne fixe (pas de regex), très rapide.
- **`grep -P`** : utilise les PCRE (*Perl-Compatible Regular Expressions*), la syntaxe la plus riche (`\d`, `\w`, `\s`, lookaheads, etc.).

```bash
# PCRE : extraire les URLs avec lookbehind
grep -oP '(?<=href=")[^"]+' page.html

# PCRE : \d pour les chiffres, \w pour les caractères de mot
grep -P "\d{4}-\d{2}-\d{2}" fichier.txt    # dates YYYY-MM-DD
grep -P "\bimport\s+\w+" programme.py

# ERE : alternatives et groupes
grep -E "(ERROR|WARN|CRIT)" /var/log/syslog
grep -E "^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])" fichier.txt

find avancé : combinaisons et actions#

Nous avons introduit find au chapitre précédent. Explorons ici ses capacités combinatoires et ses actions avancées.

Combinaisons logiques#

# AND implicite (critères successifs)
find /var/log -name "*.log" -size +1M -mtime -7

# AND explicite
find /var/log -name "*.log" -and -size +1M

# OR
find /home -name "*.jpg" -or -name "*.png" -or -name "*.gif"
find /home \( -name "*.jpg" -o -name "*.png" \)

# NOT
find /etc -not -name "*.bak"
find /etc ! -name "*.bak"    # syntaxe alternative

# Combinaison complexe : fichiers Python modifiés récemment
# mais pas dans les répertoires __pycache__ ni .git
find . \( -name "*.py" -not -path "*/__pycache__/*" \
       -not -path "*/.git/*" \) -mtime -3

Actions avancées#

# -exec commande {} \; : exécuter une commande pour chaque fichier
find /tmp -mtime +7 -exec rm -v {} \;

# -exec commande {} + : passer tous les fichiers en un seul appel
find /tmp -mtime +7 -exec rm -v {} +

# -execdir : exécuter la commande dans le répertoire du fichier
# (plus sûr que -exec pour éviter les race conditions)
find /home -name "*.py" -execdir python3 -m py_compile {} \;

# -ok : comme -exec mais demande confirmation pour chaque fichier
find /home/alice -name "*.bak" -ok rm {} \;

# -print : afficher le chemin (action par défaut)
find /etc -name "*.conf" -print

# -print0 : afficher avec \0 comme séparateur (pour les noms avec espaces)
find /home -name "* *" -print0 | xargs -0 ls -l

# -printf : affichage formaté
find /var/log -name "*.log" -printf "%p\t%s\t%TY-%Tm-%Td\n"
# %p = chemin, %s = taille, %TY-%Tm-%Td = date année-mois-jour

# Combiner find et xargs (plus efficace que -exec pour de grandes listes)
find . -name "*.pyc" -print0 | xargs -0 rm
find . -name "*.py" -print0 | xargs -0 grep -l "deprecated"

# -delete : supprimer les fichiers trouvés (plus rapide que -exec rm)
find /tmp -mtime +30 -delete
find . -name "*.pyc" -delete
find . -name "__pycache__" -type d -exec rm -r {} +

Exemple 16 (Cas d’usage find avancés)

# Trouver les fichiers dupliqués (même taille) — première étape d'un déduplicateur
find /home -type f -size +1M -printf "%s\t%p\n" | sort -n | \
  awk '{if($1==prev) print $2; prev=$1}'

# Trouver les fichiers de configuration qui ont été modifiés récemment
find /etc -name "*.conf" -newer /etc/os-release -type f

# Archiver les logs de plus de 30 jours
find /var/log -name "*.log" -mtime +30 \
  -exec gzip -v {} \;

# Corriger les permissions de tous les fichiers d'un projet web
find /var/www/html -type f -exec chmod 644 {} +
find /var/www/html -type d -exec chmod 755 {} +

# Trouver les scripts sans shebang
find /opt/scripts -name "*.sh" -type f | while read f; do
    head -1 "$f" | grep -q "^#!" || echo "Sans shebang : $f"
done

# Trouver et supprimer les fichiers temporaires d'un projet
find . \( -name "*.pyc" -o -name "*.pyo" -o -name "__pycache__" \
       -o -name ".DS_Store" -o -name "Thumbs.db" \) -delete

## locate et la base de données de fichiers

`find` est puissant mais peut être lent sur de grandes arborescences car il parcourt le système de fichiers en temps réel. **`locate`** est une alternative rapide qui interroge une **base de données pré-construite** de tous les fichiers du système.

```bash
# Installer locate (s'il n'est pas disponible)
sudo apt install plocate   # version moderne et rapide
# ou
sudo apt install mlocate   # version classique

# Mettre à jour la base de données (exécuté automatiquement par cron)
sudo updatedb

# Chercher un fichier par nom (insensible à la casse par défaut avec plocate)
locate nginx.conf

# -i : insensible à la casse (avec mlocate)
locate -i "*.PDF"

# -r : utiliser une regex
locate -r "\.conf$"

# -c : compter le nombre de résultats
locate -c "*.log"

# -l n : limiter le nombre de résultats
locate -l 10 "*.conf"

# Limites de locate vs find :
# - locate peut retourner des fichiers qui ont été supprimés depuis la dernière
#   mise à jour de la base de données
# - locate ne peut pas filtrer par permissions, taille ou date de modification
# - find est toujours à jour ; locate est rapide mais potentiellement périmé

which, whereis et type#

Ces trois commandes permettent de localiser les exécutables et d’obtenir des informations sur les commandes.

which — trouver le chemin d’un exécutable#

# Trouver où se trouve une commande dans le PATH
which ls              # /usr/bin/ls
which python3         # /usr/bin/python3
which bash            # /usr/bin/bash

# Afficher toutes les occurrences dans le PATH (pas seulement la première)
which -a python       # peut retourner /usr/bin/python et /usr/local/bin/python

# Vérifier si une commande est disponible dans un script
if which docker > /dev/null 2>&1; then
    echo "Docker est installé"
else
    echo "Docker n'est pas installé"
fi

whereis — localiser binaire, sources et pages de manuel#

# Localiser le binaire, les sources et la page de manuel d'une commande
whereis bash
# bash: /usr/bin/bash /etc/bash.bashrc /usr/share/doc/bash /usr/share/man/man1/bash.1.gz

# -b : seulement les binaires
whereis -b gcc

# -m : seulement les pages de manuel
whereis -m ls

# -s : seulement les sources
whereis -s bash

type — identifier la nature d’une commande#

type est une commande intégrée (builtin) de Bash particulièrement utile. Elle indique comment Bash interpréterait une commande donnée.

# Identifier le type d'une commande
type ls
# ls is /usr/bin/ls  (programme externe)

type cd
# cd is a shell builtin  (commande intégrée à Bash)

type ll
# ll is aliased to 'ls -alF --color=auto'  (alias)

type grep
# grep is /usr/bin/grep  (programme externe)

# -a : afficher toutes les définitions (commande externe, alias, fonction…)
type -a python
# python is aliased to 'python3'
# python is /usr/bin/python

# -t : afficher seulement le type (alias, keyword, function, builtin, file)
type -t ls        # file
type -t cd        # builtin
type -t if        # keyword
type -t ll        # alias
type -t mafonction # function (si définie)

# Vérifier si quelque chose est une fonction Bash
type -t mafonction

Remarque 13

La distinction entre builtins et programmes externes a des implications pratiques. Les builtins (cd, echo, export, read, source, test, [, etc.) sont exécutés directement par le shell sans créer un nouveau processus. Les programmes externes (ls, grep, find, awk) requièrent un fork() + exec() — deux appels système. Dans les scripts traitant de grandes quantités de données, privilégier les builtins ou les outils qui évitent de créer des processus inutiles peut améliorer significativement les performances.

Schéma : pipeline grep avec regex#

Hide code cell source

fig, axes = plt.subplots(1, 2, figsize=(18, 9))

# --- Graphique 1 : pipeline de traitement grep ---
ax = axes[0]
ax.set_xlim(-0.5, 14)
ax.set_ylim(-1, 10)
ax.axis('off')
ax.set_title('Pipeline grep : de la source au résultat filtré',
             fontsize=13, fontweight='bold')

palette = sns.color_palette("muted", 10)

def draw_pipeline_box(ax, x, y, w, h, color, title, subtitle=""):
    b = patches.FancyBboxPatch(
        (x, y), w, h, boxstyle="round,pad=0.15",
        facecolor=color, edgecolor=color, alpha=0.2, linewidth=2)
    ax.add_patch(b)
    border = patches.FancyBboxPatch(
        (x, y), w, h, boxstyle="round,pad=0.15",
        facecolor='none', edgecolor=color, linewidth=2)
    ax.add_patch(border)
    y_text = y + h / 2 + (0.15 if subtitle else 0)
    ax.text(x + w / 2, y_text, title, ha='center', va='center',
            fontsize=10, fontweight='bold', color=color)
    if subtitle:
        ax.text(x + w / 2, y - 0.25, subtitle,
                ha='center', va='top', fontsize=8,
                color='#555555', style='italic')

# Étapes du pipeline
steps = [
    # (x, y, w, h, couleur, titre, sous-titre)
    (0.2, 7.5, 3.2, 1.5, palette[0],
     "Source d'entrée", "fichier.log\n/var/log/syslog\npipeline |"),
    (0.2, 5.0, 3.2, 1.5, palette[1],
     "Lecture ligne à ligne", "chaque ligne\nest traitée\nséparément"),
    (0.2, 2.5, 3.2, 1.5, palette[2],
     "Évaluation du motif", "regex compilée\nappliquée\nà chaque ligne"),
    (0.2, 0.0, 3.2, 1.5, palette[3],
     "Sortie filtrée", "lignes\ncorrespondantes\nvers stdout"),
]

for (x, y, w, h, color, title, subtitle) in steps:
    draw_pipeline_box(ax, x, y, w, h, color, title, subtitle)

# Flèches entre étapes
for i in range(len(steps) - 1):
    _, y_top, _, h, _, _, _ = steps[i]
    _, y_bot, _, _, _, _, _ = steps[i + 1]
    mid_x = steps[i][0] + steps[i][2] / 2
    ax.annotate('', xy=(mid_x, y_bot + steps[i+1][3]),
                xytext=(mid_x, y_top),
                arrowprops=dict(arrowstyle='->', color='#444444', lw=2))

# Options de grep sur le côté
options_data = [
    (5.0, 8.0, palette[0], "-r / -R", "récursif"),
    (5.0, 7.0, palette[1], "-i", "insensible casse"),
    (5.0, 6.0, palette[2], "-n", "numéro de ligne"),
    (5.0, 5.0, palette[3], "-l / -L", "noms de fichiers"),
    (5.0, 4.0, palette[4], "-v", "inverser"),
    (5.0, 3.0, palette[5], "-E", "regex étendue"),
    (5.0, 2.0, palette[6], "-c", "compter"),
    (5.0, 1.0, palette[7], "-o", "only matching"),
    (5.0, 0.0, palette[8], "-A/-B/-C", "contexte"),
]

ax.text(8.5, 9.2, "Options grep", ha='center', va='center',
        fontsize=11, fontweight='bold', color='#333333')

for (x, y, color, opt, desc) in options_data:
    b = patches.FancyBboxPatch(
        (x, y), 5.5, 0.75, boxstyle="round,pad=0.1",
        facecolor=color, edgecolor=color, alpha=0.2, linewidth=1.5)
    ax.add_patch(b)
    ax.text(x + 1.5, y + 0.375, opt, ha='center', va='center',
            fontsize=9, fontweight='bold', color=color,
            fontfamily='monospace')
    ax.text(x + 3.5, y + 0.375, desc, ha='center', va='center',
            fontsize=8.5, color='#444444')

# --- Graphique 2 : exemples de regex visuels ---
ax2 = axes[1]
ax2.set_xlim(-0.5, 13)
ax2.set_ylim(-0.5, 10.5)
ax2.axis('off')
ax2.set_title('Anatomie des expressions régulières',
              fontsize=13, fontweight='bold')

regex_examples = [
    # (motif, explication, exemple_match, couleur)
    ("^ERROR",
     "Lignes commençant par ERROR",
     "ERROR: connexion refusée", palette[0]),
    ("[0-9]{1,3}",
     "Séquence de 1 à 3 chiffres",
     "IP: 192.168.1.10", palette[1]),
    ("https?://",
     "http:// ou https://",
     "https://exemple.com", palette[2]),
    ("\\.conf$",
     "Fichiers se terminant par .conf",
     "nginx.conf", palette[3]),
    ("[a-zA-Z]+@[a-z]+\\.[a-z]{2,}",
     "Adresse email simplifiée",
     "alice@exemple.fr", palette[4]),
    ("(ERROR|WARN|CRIT)",
     "L'un de ces trois mots",
     "WARN: espace disque faible", palette[5]),
    ("^[[:space:]]*$",
     "Lignes vides ou avec espaces",
     "(ligne blanche)", palette[6]),
    ("\\bimport\\b",
     "Mot 'import' (pas 'reimport')",
     "import numpy as np", palette[7]),
]

for i, (motif, expl, exemple, color) in enumerate(regex_examples):
    y = 9.5 - i * 1.2

    # Fond de la ligne
    bg = patches.FancyBboxPatch(
        (-0.2, y - 0.55), 13, 1.0,
        boxstyle="round,pad=0.1",
        facecolor=color, edgecolor=color, alpha=0.08, linewidth=1)
    ax2.add_patch(bg)

    # Motif (monospace)
    ax2.text(0.0, y, motif, ha='left', va='center',
             fontsize=9, fontweight='bold', color=color,
             fontfamily='monospace',
             bbox=dict(boxstyle='round,pad=0.2', facecolor=color,
                       alpha=0.15, edgecolor=color, linewidth=1.2))

    # Explication
    ax2.text(4.5, y + 0.2, expl, ha='left', va='center',
             fontsize=8.5, color='#444444')

    # Exemple de correspondance
    ax2.text(4.5, y - 0.2, f"ex : {exemple}", ha='left', va='center',
             fontsize=8, color='#666666', style='italic')

ax2.text(0.0, 10.2, "Motif", ha='left', fontsize=10,
         fontweight='bold', color='#333333')
ax2.text(4.5, 10.2, "Signification / Exemple", ha='left', fontsize=10,
         fontweight='bold', color='#333333')
ax2.axhline(9.9, xmin=0, xmax=1, color='#cccccc', lw=1.5)

plt.tight_layout()
plt.show()
_images/05327e54eec11e3bcaadcf6cd017b72783591af0d482bc8bc1e4b520ae078bdf.png

Résumé#

Ce chapitre a couvert les outils essentiels pour lire et chercher du contenu sous Linux :

  • Lecture de fichiers : cat pour afficher rapidement, less pour naviguer de façon interactive, head/tail pour les débuts/fins de fichiers, tail -f pour surveiller un fichier en temps réel, wc pour compter lignes, mots et octets.

  • grep est l’outil central de recherche textuelle. Ses options essentielles sont -i (casse), -r (récursif), -n (numéros de ligne), -l/-L (noms de fichiers), -v (inversion), -E (regex étendue), -c (comptage), -A/-B/-C (contexte), -o (portion correspondante), -P (PCRE).

  • Les expressions régulières (BRE, ERE, PCRE) permettent de décrire des motifs complexes : ancres (^, $, \b), métacaractère universel (.), classes de caractères ([a-z], [:digit:]), quantificateurs (*, +, ?, {n,m}), alternatives (|), groupes (()).

  • find avancé : combinaisons logiques (-and, -or, -not), actions (-exec, -execdir, -delete, -printf), intégration avec xargs pour traiter de grandes listes de fichiers efficacement.

  • locate / plocate offrent une recherche rapide via une base de données pré-indexée, complémentaire à find pour les recherches par nom.

  • which localise un exécutable dans le PATH, whereis trouve binaire, sources et manuel, type révèle la nature d’une commande (builtin, alias, fonction, programme externe).

Dans le prochain chapitre, nous aborderons les redirections et les pipes — les mécanismes qui permettent de composer des pipelines de traitement puissants en connectant les entrées et sorties des commandes.