Newer
Older
cours-unix-shell / sed / README.md
# sed - UNIX

Sed (pour **S**tream **ED**itor) est un éditeur non interactif de texte.  
Il permet d'appliquer une certain nombre de commandes à un fichier puis d'en
afficher le résultat (sans modifier le fichier de départ) sur la sortie
standard.  
Comme avec toute commande unix, il est possible de rediriger la sortie vers un
fichier résultat.

## Substitution

La commande suivante lit un fichier `file.txt` et affiche ses lignes sur la
sortie standard en remplaçant la chaîne « `Dilib` » par la chaîne « `DILIB` ».

```bash
sed 's/Dilib/DILIB/' file.txt
```

Il est conseillé d'entourer les commandes par des apostrophes simples, pour
éviter que le shell n'interprète les [caractères
spéciaux](../shell/parametres.md#caractères-spéciaux) (`.*[]^$\`).

> ⚠ Cette commande ne remplace que la première occurrence de « `Dilib` » sur chaque
> ligne du fichier.  
> S'il y en a deux, la deuxième ne sera pas remplacée, à moins d'utiliser
> l'option `g` en fin de commande :
>
> ```bash
> sed 's/Dilib/DILIB/g' file.txt
> ```

Si on veut faire deux remplacements sur la même ligne de commandes, on peut utiliser :

```bash
sed -e 's/Dilib/DILIB/g' -e 's/Jacques Ducloy/Monsieur Dilib/g' file.txt
```

> ⚠ Le `-e` est obligatoire pour distinguer la deuxième commande d'un nom de
> fichier qui n'en est jamais précédé.
>
> 📗 Les commandes sont effectuées sur chaque ligne dans leur ordre
> d'apparition, ce qui veut dire que « `Jacques Ducloy` » sera transformé en «
> `Monsieur Dilib` » après la substitution de « `Dilib` » par « `DILIB` », il
> restera donc des « `Dilib` » sur la sortie standard.

### Rappel sur les expressions régulières

|          |                                                                                                        |
| -------- | ------------------------------------------------------------------------------------------------------ |
| `^`      | début de ligne                                                                                         |
| `$`      | fin de ligne                                                                                           |
| `[]`     | classe de caractères (exemples : `[A-Z]` correspond à toutes les lettres majuscules)                   |
| `[^...]` | classe de caractères correspondant à n'importe quels caractères sauf ceux qui suivent le caractère `^` |
|          | Exemple : `[^:]` correspond à tous les caractères sauf le `:`.                                         |
| `*`      | le caractère précédant `*` répété de 0 à n fois                                                        |
| `+`      | le caractère précédant `+` répété de 1 à n fois                                                        |
| `?`      | le caractère précédant `?` présent de 0 à 1 fois                                                       |

### Expressions régulières

On peut utiliser des expressions régulières dans les chaînes à remplacer (donc,
il faut banaliser les caractères spéciaux dans cette chaîne).

```bash
sed -e 's/Jacques D[uU][cC][lL][oO][yY]/Monsieur Dilib/g' fichier
```

> 📗 Le caractère `*` englobe autant de caractères qu'il peut, ce qui veut dire que
>
> ```bash
> sed 's/ré.*duction/réduction/g' fichier
> ```
>
> transformera le fichier
>
> ```txt
> do ré mi fa sol la si duction ah bon duction la suite
> ```
>
> en
>
> ```txt
> do réduction la suite
> ```
>
> et non en
>
> ```txt
> do réduction ah bon duction la suite
> ```

## Récupération

Les opérateurs `\(` et `\)` sauvent leur contenu et permettent leur récupération
par l'utilisation de `\1`, `\2`, etc.

```bash
sed -e 's/^\([A-Z][A-Za-z]*\), \([A-Z][A-Za-z]*\)/\2 \1/' fichier
```

Remplacera les « `Nom, Prénom` » en début de chaque ligne du fichier (quand il
en trouve) par « `Prénom Nom` ».

## Fichier de commandes

Si vous avez beaucoup de commandes, vous pouvez les rassembler dans un fichier
comme celui-là :

```bash
# Fichier "exemple.sed"
# Il ne peut y avoir de commentaires que dans un bloc au début du
# fichier.
s/É/É/g
s/À/À/g
s/Ç/Ç/g
```

Pour appeler ce fichier, il faut utiliser l'option `-f` :

```bash
sed -f exemple.sed fichier
```

Une autre solution consiste à en faire un script exécutable (à la manière d'un
script shell) :

```bash
#!/usr/bin/sed -f
# Table de transcodage de ISO-8859-1 vers HTML
# Fichier "exemple2.sed"
s/É/É/g
s/À/À/g
s/Ç/Ç/g
```

Mais il ne faut pas oublier de lui donner les droits en exécution, pour pouvoir
l'appeler ainsi :

```bash
chmod u+x exemple2.sed
./exemple2.sed fichier
```

> ⚠ Un fichier de commandes sed doit toujours se terminer par un passage à la
> ligne, sinon la dernière commande n'est pas prise en compte!

> ⚠ De la même manière, toutes les lignes à traiter doivent finir par un retour
> à la ligne (en particulier la dernière)!

## Référence

- <http://www.shellunix.com/sed.html> La commande **sed**
- <https://regex101.com/> **Regex 101**, pour fabriquer et comprendre vos
  expressions régulières
- <https://jex.im/regulex/> **Regulex**, pour visualiser la structure des
  expressions régulières
- <https://github.com/regexhq> **RegexHQ** pour trouver facilement des expressions
  régulières pour toutes sortes de cas d'usages

[Précédent](../shell/tp.md) - [Suivant](./tp.md)