Laisser un commentaire

Découvrir la commande sed par l'exemple

Sed peut faire des choses qui prendraient des heures à faire avec une interface graphique. Exemple ? Renommer 1500 documents d’un coup ou encore modifier du texte dans des centaines de fichiers à la fois ! Introduction et résumé des commandes.

sed [OPTION]... {script-only-if-no-other-script} [input-file]...

# Commandes :
sed -e --> commande uniligne
sed -f fichier --> passage de commande par un script
sed -i --> modifie directement le fichier source au lieu de rediriger vers la sortie standard

Avant de commencer, sachez qu’une grande partie de la puissance de sed provient des expressions régulière. Si vous ne les connaissez pas ou n’êtes pas bien à l’aise avec ces dernières, jetez un coup d’œil à mon article sur les regex.

Créons un fichier de test, test.txt, avec le contenu suivant :

Voilà un simple fichier de test

#ceci représente un commentaire

ici_un_possible_nom de fichier

pareil avec espaces

pareil-avec-tirets

Si on invoque sed sans argument, il retourne la totalité du texte.

$ sed '' test.txt
Voilà un simple fichier de test

#ceci représente un commentaire

ici_un_possible_nom de fichier

pareil avec espaces

pareil-avec-tirets

Jusque là c’est un peu inutile, voyons donc ce dont cette commande est capable.

Suppression

Supprimer une ligne selon son numéro

Il faut pour cela utiliser l’option d, pour delete.

$ sed '1d;4d' test.txt

#ceci représente un commentaire
ici_un_possible_nom de fichier

pareil avec espaces

pareil-avec-tirets

Vous notez que le point-virgule “;” fait ici office de séparateur. On supprime donc les lignes 1 et 4 (la 4 ne contenant qu’un retour à la ligne).

On peut également spécifier un intervalle en utilisant la virgule : sed '1,4d' test.txt supprimera les lignes 1 à 4.

Supprimer une ligne selon une REGEX

Toujours avec l’option d.

$ sed '/^#/d' test.txt
Voilà un simple fichier de test


ici_un_possible_nom de fichier

pareil avec espaces

pareil-avec-tirets

Les slash servent de délimiteurs. On supprime ici toutes le lignes commençants par “#”.

On peut aussi l’utiliser avec des intervales. Cela supprimera toutes les lignes comprises entre les deux match (matchs inclus).

$ sed '/^#/d;/_/d' test.txt
Voilà un simple fichier de test



pareil avec espaces

pareil-avec-tirets

Cette fois, nous avons supprimé toutes les lignes comprises entre une ligne commençant par “#” et une ligne comportant “_”.

Plus puissant encore, on peut mélanger les deux ! Exemple, je veux supprimer la première ligne et toutes les lignes qui commencent par “#”.

$ sed '1d;/^#/d' test.txt


ici_un_possible_nom de fichier

pareil avec espaces

pareil-avec-tirets

Filtrage

C’est exactement l’inverse de ce que nous venons de faire. Ici on choisit de ne rien afficher par défaut. On veut par exemple n’afficher que les lignes qui commencent par dièse ? Easy, on va utiliser l’option silencieux -n, avec la commande print p :

sed -n '/^#/p' test.txt
#ceci représente un commentaire

Par ailleurs, on peut choisir de n’afficher qu’une ligne, ou une intervalle.

# juste la ligne 5
sed -n 5p hexdump

# de la ligne 5 à la 10
sed -n 5,10p

La substitution

La substitution permet de remplacer un motif par un autre. On vient par exemple de récupérer un document dans lequel toutes les occurrences de votre nom contiennent une faute. Rien de plus facile à corriger.

$ sed 's/George Dupond/Georges Dupont/' synthese-dsi.txt

Note : si vous voulez utilisez les REGEX, c’est tout à fait possible ! Pensez d’ailleurs à utiliser l’option -r qui permet la syntaxe étendue.

Il peut arriver que vous vouliez remplacer des retours à la ligne. Il faudra pour cela utiliser l’option -z. Par exemple, vous avez un fichier texte content ceci :

Ce
site
est
génial
!

La substitution avec l’option -z permettra de remplacer les retours à la ligne.

sed -z 's/\n/ /g' test.txt
Ce site est génial !

La translitération

Sous ce terme un peu complexe se cache un concept assez simple à comprendre. La translitération veut dire changer de lettre, tout simplement. Par exemple, vous avez un problème d’encodage avec les accents et vous voulez tous les faire sauter. Here you go.

$ sed 'y/éèêë/eeee/'

Commandes groupées

Voici une possibilité qui peut faire gagner un temps précieux. Il est possible d’appliquer plusieurs commandes à la fois en utilisant les accolades “{“ et “}”.

# remplacer tous les "e" accentués par des "e"
# et réécrire "Dupond" avec un "t" aux lignes 3 et 4
sed '2,6 {y/éèê/eee/;s/Dupond/Dupont/g}' fichiersource.txt

# même chose mais sur les lignes qui commencent par "#"
sed '/^#/ {y/éèê/eee/;s/Dupond/Dupont/g}' fichiersource.txt

Évidemment, on peut également utiliser les regex dans la substitution.

Exemples concrets

Renommer des fichiers

Vous venez de télécharger la dernière saison de votre série préférée et tous les noms des fichiers sont rendus illisibles à cause des “-“ à la place des espaces ? Sachant que c’est pour éviter d’avoir des problèmes de compatibilité à cause des espaces, vous préféreriez les remplacer par des underscore (“_”), qui sont plus lisibles.

$ for f in *.mp4; do fn=`echo $f|sed 's/-/_/g'`; mv "$f" "$fn"; done

Nous avons ici utilisé sed conjointement à une boucle for do done. Bien entendu, nous sommes ici dans le dossier contenant les videos. Voici ce que fait ce code de manière détaillée.

Modifier du texte dans plusieurs fichiers à la fois

Ça c’est vraiment quelque chose que tout le monde devrait connaitre (on ne parle même pas des développeurs…). Vous avez par exemple une centaine de fichiers avec une même information qui vient de changer… Vous n’allez tout de même pas les ouvrir un par un et les modifier manuellement. Sed est là pour ça !

# exemple avec des fichiers php, on admet être dans le bon répertoire
$ for f in *.php; do sed -i -e 's/ancienne-adresse/nouvelle-adresse/' "$f"; done

On utilise ici l’option -i, qui modifie directement le fichier au lieu de rediriger vers la sortie standard. Une utilisation intéressante de cette option est qu’il est possible de conserver une sauvegarde du fichier avant modification. Pour cela, il suffit de mettre un suffixe à l’option -i :

$ for f in *.php; do sed -i.bak -e 's/ancienne-adresse/nouvelle-adresse/' "$f"; done

Vous aurez ainsi vos fichiers .php modifiés, et les fichiers avant modification seront de la forme .php.bak.

Vous pouvez également rediriger tous les nouveaux fichiers (donc ceux modifiés) dans un nouveau répertoire en utilisant simplement un flux de redirection >. Créons donc le dossier new.

$ for f in *.php; do sed 's/ancienne-adresse/nouvelle-adresse/' "$f" > new/"$f"; done

Je ne pense pas avoir besoin de vous expliquer ici comment marche la commande ! Tous vos fichiers modifiés se trouveront dans le dossier new, tandis que les anciens n’auront pas bougé.

Même parmi les développeurs, nombreux sont ceux qui ne savent pas se servir de sed. C’est vraiment dommage car cette commande permet un énorme gain en productivité. N’hésitez pas à partager cette article autour de vous. Vos amis et collègues vous en sauront gré !

Par ailleurs, si la ligne de commande vous intéresse, jetez un œil mon article sur les commandes Linux les plus pratiques.

Commentaires

Rejoignez la discussion !

Vous pouvez utiliser Markdown pour les liens [ancre de lien](url), la mise en *italique* et en **gras**. Enfin pour le code, vous pouvez utiliser la syntaxe `inline` et la syntaxe bloc

```
ceci est un bloc
de code
```