# 3 - Lire, rechercher et traiter du texte

Afficher, filtrer, rechercher et transformer efficacement des fichiers texte.

# 3.1 - Lire un fichier avec cat, less, head et tail

## Afficher un petit fichier

```bash
cat /etc/os-release
cat -n notes.txt           # numéroter les lignes
```

`cat` affiche tout le contenu d'un coup. Il convient aux petits fichiers, mais devient peu pratique pour un journal de plusieurs gigaoctets.

Assembler plusieurs fichiers :

```bash
cat partie1.txt partie2.txt > document-complet.txt
```

## Parcourir avec less

```bash
less /var/log/syslog
less +F /var/log/syslog    # suivre les ajouts ; Ctrl+C pour revenir à less
```

Touches essentielles :

| Touche | Action |
|---|---|
| `Espace` / `b` | page suivante / précédente |
| `g` / `G` | début / fin |
| `/erreur` | rechercher vers le bas |
| `n` / `N` | occurrence suivante / précédente |
| `F` | suivre les nouvelles lignes |
| `q` | quitter |

`less` ne charge pas nécessairement tout le fichier en mémoire et convient donc mieux aux gros fichiers.

## Début et fin d'un fichier

```bash
head fichier.log
head -n 20 fichier.log
tail fichier.log
tail -n 50 fichier.log
```

Suivre un journal en direct :

```bash
tail -f application.log
tail -F application.log
```

`-F` continue de suivre le nom même si le fichier est recréé lors d'une rotation de journaux. Quitter avec `Ctrl` + `C`.

## Extraire une plage de lignes

```bash
sed -n '20,40p' fichier.txt
```

Cette commande affiche les lignes 20 à 40 sans modifier le fichier.

## Afficher les caractères invisibles

```bash
cat -A fichier.txt
sed -n 'l' fichier.txt
```

Utile pour repérer tabulations, espaces finaux et fins de ligne Windows.

## Encodage et fins de ligne

```bash
file -i fichier.txt
```

Convertir un fichier Windows CRLF vers Linux LF si `dos2unix` est installé :

```bash
dos2unix script.sh
```

Avant de lancer un script téléchargé, l'afficher et l'examiner :

```bash
less script.sh
file script.sh
```

Afficher un fichier est normalement non destructif, mais son contenu peut comporter des séquences de terminal indésirables. Pour une source non fiable, `less` est souvent préférable à l'exécution ou au copier-coller aveugle.

# 3.2 - Rechercher avec grep, rg, find et locate

## Rechercher du texte avec grep

```bash
grep 'erreur' application.log
grep -i 'erreur' application.log       # ignorer la casse
grep -n 'erreur' application.log       # afficher les numéros de ligne
grep -v '^#' fichier.conf              # exclure les commentaires
grep -RIn '192.168.25.1' /etc           # recherche récursive
```

Afficher du contexte :

```bash
grep -n -C 3 'failed' service.log       # 3 lignes avant et après
grep -n -A 5 'failed' service.log       # 5 lignes après
grep -n -B 2 'failed' service.log       # 2 lignes avant
```

Expressions régulières étendues :

```bash
grep -En 'error|failed|denied' application.log
grep -E '^[0-9]{4}-[0-9]{2}-[0-9]{2}' application.log
```

## Rechercher rapidement avec rg

`rg` désigne **ripgrep**. Il est très rapide et ignore par défaut certains fichiers cachés ou exclus par `.gitignore`.

```bash
rg 'motif' .
rg -n -i 'motif' /etc
rg --hidden 'motif' .
rg -g '*.yml' 'password' .
```

Il n'est pas installé par défaut partout. Utiliser `grep -R` comme solution universelle.

## Rechercher des fichiers avec find

```bash
find . -type f -name '*.log'
find /var/log -type f -iname '*error*'
find . -type d -name 'cache'
find . -type f -size +100M -print
find . -type f -mtime -7 -print       # modifiés depuis moins de 7 jours
find . -maxdepth 2 -type f -print
```

Exécuter une commande sur chaque résultat :

```bash
find . -type f -name '*.conf' -exec file {} \;
```

Pour les noms contenant des espaces ou retours à la ligne, préférer des séparateurs nuls :

```bash
find . -type f -print0 | xargs -0 file
```

## Recherche indexée avec locate

```bash
locate sshd_config
sudo updatedb
```

`locate` interroge une base mise à jour périodiquement : il est rapide, mais peut afficher un fichier qui vient d'être supprimé ou manquer un fichier récent.

## Rechercher une commande disponible

```bash
command -v ssh
type -a python
```

Toujours délimiter précisément une recherche sous `/` : elle peut être lente, rencontrer des permissions refusées et parcourir des systèmes de fichiers distants.

# 3.3 - Redirections, tubes et tee

Les commandes utilisent trois flux standards :

| Numéro | Flux | Rôle |
|---:|---|---|
| 0 | entrée standard, `stdin` | données reçues par la commande |
| 1 | sortie standard, `stdout` | résultat normal |
| 2 | erreur standard, `stderr` | avertissements et erreurs |

## Rediriger la sortie

```bash
commande > resultat.txt       # remplacer le fichier
commande >> resultat.txt      # ajouter à la fin
commande 2> erreurs.txt       # erreurs seulement
commande > tout.txt 2>&1      # sortie et erreurs dans le même fichier
commande &> tout.txt          # raccourci Bash
```

`>` vide le fichier avant d'exécuter la commande. Vérifier le chemin et préférer `>>` lorsqu'un historique doit être conservé.

Ignorer une sortie :

```bash
commande > /dev/null
commande > /dev/null 2>&1
```

## Fournir une entrée

```bash
sort < noms.txt
```

Document intégré :

```bash
cat <<'EOF'
Le contenu $VARIABLE reste littéral
Deuxième ligne
EOF
```

## Relier des commandes avec un tube

Le tube `|` transmet la sortie standard d'une commande à l'entrée de la suivante.

```bash
ps aux | grep '[s]shd'
journalctl -b | grep -i 'error'
find . -type f | wc -l
```

Une chaîne se lit de gauche à droite : produire, filtrer, transformer puis résumer.

```bash
cut -d: -f1 /etc/passwd | sort | uniq
```

## Voir et enregistrer avec tee

```bash
ip addr | tee diagnostic-reseau.txt
ip addr | tee -a diagnostic-complet.txt
```

Écrire dans un fichier protégé :

```bash
printf '%s\n' 'option=valeur' | sudo tee /etc/application.conf
```

`tee` affiche aussi ce qu'il écrit. Ajouter `> /dev/null` pour masquer cette copie d'écran.

## Codes d'erreur dans un pipeline

Par défaut, le shell retourne souvent le code de la dernière commande du pipeline. Dans un script Bash sensible :

```bash
set -o pipefail
commande1 | commande2
echo "$?"
```

`pipefail` signale l'échec d'une commande intermédiaire. Dans un terminal, voir les codes de tout le dernier pipeline :

```bash
printf '%s\n' "${PIPESTATUS[@]}"
```

Ne mélangez pas au hasard `sudo`, les redirections et les tubes : chaque partie peut s'exécuter avec des privilèges différents.

# 3.4 - Trier et transformer avec sort, uniq, cut, sed et awk

Les petits outils Unix sont conçus pour être combinés. Ils permettent d'extraire une information sans ouvrir un tableur ou écrire un programme complet.

## Compter avec wc

```bash
wc fichier.txt
wc -l fichier.txt       # lignes
wc -w fichier.txt       # mots
wc -c fichier.txt       # octets
```

## Trier et supprimer les doublons

```bash
sort noms.txt
sort -n nombres.txt
sort -h tailles.txt
sort -r noms.txt
sort noms.txt | uniq
sort noms.txt | uniq -c | sort -nr
```

`uniq` ne regroupe que les lignes identiques adjacentes ; il est donc souvent précédé de `sort`.

## Extraire des colonnes

```bash
cut -d: -f1 /etc/passwd
cut -d';' -f1,3 inventaire.csv
```

`cut` convient aux séparateurs simples. Un CSV avec des guillemets, des retours à la ligne ou des séparateurs échappés nécessite un véritable analyseur CSV.

## Remplacer des caractères avec tr

```bash
printf '%s\n' 'bonjour' | tr '[:lower:]' '[:upper:]'
tr -d '\r' < windows.txt > linux.txt
tr ':' '\n' < /etc/passwd
```

## Transformer avec sed

Afficher sans modifier :

```bash
sed -n '1,10p' fichier.txt
sed 's/ancien/nouveau/g' fichier.txt
sed '/^#/d; /^$/d' fichier.conf
```

Créer un nouveau fichier :

```bash
sed 's/ancien/nouveau/g' fichier.txt > fichier-modifie.txt
```

La modification directe `sed -i` varie entre GNU/Linux et BSD/macOS. Créer d'abord une sauvegarde :

```bash
sed -i.bak 's/ancien/nouveau/g' fichier.txt
```

## Extraire avec awk

```bash
awk -F: '{print $1}' /etc/passwd
awk '{print NR, $0}' fichier.txt
awk '$3 > 80 {print $1, $3}' mesures.txt
df -P | awk 'NR>1 {print $6, $5}'
```

Dans `awk`, `$1` désigne le premier champ, `$0` toute la ligne et `NR` le numéro de ligne.

## Exemple combiné

Compter les shells déclarés dans `/etc/passwd` :

```bash
cut -d: -f7 /etc/passwd | sort | uniq -c | sort -nr
```

Tester d'abord les transformations sans `-i`, comparer le résultat avec `diff`, puis remplacer le fichier uniquement après validation.