La commande sed pour les nazes

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.

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).

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

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

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

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

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.

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 *.avi; 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.

  • for f in *.avi; on créé une variable f, qui prend en paramètre le nom de tous les fichiers qui se terminent par .avi ;
  • do fn=`echo $f|sed 's/-/_/g'`; on créer une nouvelle variable fn, qui prendra comme valeur le résultat de la sous-commande echo $f|sed 's/-/_/g'. Les expressions entre backquotes (`) sont substituées par leur résultat en bash.

    • echo $f|sed 's/-/_/g' on envoie à sed le contenu de $f en combinant echo et le pipe (|) afin qu’il le mette au bon format.
  • mv $f $fn; enfin, on modifie le titre avec la commande mv : change $f par $fn.
  • done, on indique que la commande est terminé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 modifiee 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 seront gré !

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

Déjà 21 réponses, rejoignez la discussion !

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *