Sed fait partie de la boîte à outils standard Unix depuis la fin des années 60. Comme tout éditeur de texte, il vous aidera à modifier les fichiers texte. Cependant, contrairement aux éditeurs de texte que vous avez peut-être déjà utilisés, celui-ci est non interactif.
Cela signifie que vous spécifiez à l'avance les transformations que vous souhaitez appliquer à un fichier, puis l'outil peut appliquer ces transformations sans supervision.
La meilleure description des objectifs de conception de l'outil provient de Lee E. McMahon, le développeur principal de l'implémentation d'origine dans son article sed original :
Sed est un éditeur de contexte non interactif qui s'exécute sur le système d'exploitation UNIX. Sed est conçu pour être particulièrement utile dans trois cas :
- Pour éditer des fichiers trop volumineux pour une édition interactive confortable ;
- Pour éditer un fichier de n'importe quelle taille lorsque la séquence de commandes d'édition est trop compliquée pour être saisie confortablement en mode interactif.
- Pour effectuer efficacement plusieurs fonctions d'édition "globales" en un seul passage dans l'entrée.
Les conceptions d'objectifs (1) et (3) sont probablement moins pertinentes avec notre matériel moderne, mais la seconde reste valable. En tant qu'ajout personnel, je dirais que sed est particulièrement bien adapté aux tâches répétitives, comme lorsque vous souhaitez appliquer la même transformation à un ensemble de fichiers.
Apprenez les commandes SED de base avec ces exemples
Pour vous donner un avant-goût de la puissance de sed, je vais considérer le cas d'un développeur qui a besoin d'ajouter un en-tête de licence au-dessus de chacun des fichiers source de son projet :
[email protected]:~$ head MIT.LICENSE *.sh
==> MIT.LICENSE <==
-----8<----------------------------------------------------------------
Copyright <YEAR> <COPYRIGHT HOLDER>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
==> script1.sh <==
#!/bin/bash
echo Hello, I\'m the first script
==> script2.sh <==
#!/bin/bash
cat << EOF
Hello, I'm the second script
EOF
Non seulement j'aimerais voir le fichier de licence au-dessus de chaque script shell, mais j'aimerais aussi que l'année et l'espace réservé au droit d'auteur soient remplacés par leur valeur réelle. Ce sera notre premier cas d'utilisation.
Remarque :si vous souhaitez vous entraîner par vous-même, vous pouvez télécharger les exemples de fichiers sur mon site Web. Vous pouvez également jeter un œil à la vidéo complétant cet article :
1. Remplacement du texte dans SED
Dans mon fichier de licence, je souhaite remplacer les espaces réservés
C'est un travail parfaitement adapté à la sed substitution commande. Probablement la plus utile de toutes les commandes sed :
[email protected]:~$ sed -e 's/<YEAR>/2018/' MIT.LICENSE | head -5
-----8<----------------------------------------------------------------
Copyright 2018 <COPYRIGHT HOLDER>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
Utiliser un tube (|
), j'ai transmis la sortie de la commande sed au head
outil pour afficher uniquement les cinq premières lignes ici. Cependant, pour le sujet spécifique de notre aujourd'hui, la partie la plus intéressante est le s/<YEAR>/2018/
expression.
Sed fonctionne en traitant le fichier d'entrée une ligne à la fois. Sur chaque ligne, le substitut (s
) remplacera la première occurrence du texte entre les deux premières barres obliques (/<YEAR>/
) par le texte entre les deux derniers (/2018/
). Pensez à cela comme à la fonction de recherche-remplacement que vous avez dans un éditeur de texte graphique.
Il convient de mentionner ici que le fichier MIT.LICENSE d'origine n'a pas été modifié. Je vous laisse vérifier cela par vous-même en utilisant la commande suivante :
head -5 MIT.LICENSE
2. Remplacer le texte… à nouveau
Génial :nous avons remplacé l'espace réservé de l'année. Mais il y en a un deuxième à remplacer. Si vous avez compris l'exemple précédent, vous pourriez probablement imaginer une deuxième expression sed comme celle-ci :
's/<COPYRIGHT HOLDER>/Sylvain Leroux/'
Mais où placer ça ? Eh bien, vous avez plusieurs choix. La plus évidente si vous êtes déjà familiarisé avec le concept de redirection est de rediriger la sortie de notre première commande sed vers une deuxième instance de sed :
[email protected]:~$ sed -e 's/<YEAR>/2018/' MIT.LICENSE |
sed -e 's/<COPYRIGHT HOLDER>/Sylvain Leroux/' |
head -5
----8<----------------------------------------------------------------
Copyright 2018 Sylvain Leroux
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
Mais nous pouvons faire mieux. Depuis le -e
introduit une expression sed, nous pouvons en utiliser plusieurs dans le cadre du même appel sed, et le résultat sera le même :
# Pay special attention to the \ at the end of the lines
# specifying the *same* command continues on the
# next line:
sh$ sed -e 's/<YEAR>/2018/' \
-e 's/<COPYRIGHT HOLDER>/Sylvain Leroux/' \
MIT.LICENSE |
head -5
Enfin, vous pouvez également spécifier plusieurs commandes dans la même expression sed en les séparant par une nouvelle ligne. Ceci est particulièrement utile lorsque vous commencez à écrire des programmes sed plus complexes :
# Pay special attention to the single-quotes and
# backslash placement:
sh$ sed -e 's/<YEAR>/2018/
s/<COPYRIGHT HOLDER>/Sylvain Leroux/' \
MIT.LICENSE |
head -5
3. Insertion de texte
Nous avons maintenant remplacé les espaces réservés par leur valeur réelle. Mais nous avons encore du travail à faire avant de pouvoir insérer ce fichier de licence dans les fichiers du projet. Ces derniers étant des scripts shell, chaque ligne de la licence doit commencer par un octothorpe (#
) pour que le shell comprenne, il ne doit pas essayer d'interpréter ces lignes.
Pour cela, nous utiliserons à nouveau la commande de substitution. Quelque chose que je n'ai pas mentionné précédemment est que, contrairement à la plupart des fonctionnalités de recherche-remplacement des éditeurs d'interface graphique, le modèle de recherche n'est pas nécessairement la chaîne littérale à rechercher. En fait, il s'agit d'une expression régulière (regex). Cela signifie qu'en plus des caractères simples qui correspondent textuellement, vous pouvez utiliser des caractères qui auront une signification particulière. Par exemple, le caret (^
) représente le début de la ligne, le signe dollar ($
) la fin de la ligne, ou, comme dernier exemple, le point-étoile (.*
) désigne toute séquence de 0, 1 ou plusieurs caractères. Il existe de nombreux autres métacaractères de ce type, mais pour l'instant, c'est plus que suffisant.
Alors pour insérer du texte au début d'une ligne, une option est de substituer le début de la ligne par ce texte :
[email protected]:~$ sed -e 's/<YEAR>/2018/' \
-e 's/<COPYRIGHT HOLDER>/Sylvain Leroux/' \
-e 's/^/# /' \
MIT.LICENSE | head -5
# -----8<----------------------------------------------------------------
# Copyright 2018 Sylvain Leroux
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
4. Effacer les lignes sélectionnées
La commande de substitution dans sed est si polyvalente que vous pouvez exprimer la plupart des transformations de texte en l'utilisant. Par exemple, pour supprimer les lignes pointillées en haut et en bas du texte de la licence, je pourrais écrire ceci :
[email protected]:~$ sed -e 's/<YEAR>/2018/' \
-e 's/<COPYRIGHT HOLDER>/Sylvain Leroux/' \
-e 's/^/# /' \
-e 's/^.*----.*$//' \
MIT.LICENSE | head -5
# Copyright 2018 Sylvain Leroux
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
Cette dernière substitution a remplacé par la chaîne vide tout le texte :
Symbole | Description |
---|---|
^ | Commencer au début de la ligne |
.* | Suivi d'une séquence quelconque de 0, 1 ou plusieurs caractères |
---- | Suivi de 4 traits d'union |
.* | Suivi d'une séquence quelconque de 0, 1 ou plusieurs caractères |
$ | Suivi de la fin de la ligne |
En bref, cela remplacera toute la ligne par la chaîne vide if il contient quatre tirets d'affilée. Mais la ligne vide elle-même reste dans la sortie et apparaîtra comme une ligne vide.
En fonction de vos besoins et de vos goûts, vous pouvez également envisager la solution alternative ci-dessous. Je vous laisse examiner cela en détail pour repérer les changements dans la commande et identifier par vous-même quelles ont été les conséquences sur le résultat :
[email protected]:~$ sed -e 's/<YEAR>/2018/' \
-e 's/<COPYRIGHT HOLDER>/Sylvain Leroux/' \
-e 's/^.*----.*$//' \
-e 's/^/# /' \
MIT.LICENSE | head -5
Si vous trouvez l'expression régulière utilisée pour effacer la ligne un peu trop complexe, nous pouvons également profiter d'une autre fonctionnalité sed. Presque toutes les commandes peuvent prendre une adresse facultative avant le nom de la commande. S'il est présent, il limitera la portée de la commande aux lignes correspondantes cette adresse :
[email protected]:~$ sed -e 's/<YEAR>/2018/' \
-e 's/<COPYRIGHT HOLDER>/Sylvain Leroux/' \
-e 's/^/# /' \
-e '/----/s/^.*$//' \
MIT.LICENSE | head -5
Désormais, la dernière commande de substitution ne sera appliquée qu'aux lignes correspondant (c'est-à-dire "contenant") quatre tirets d'affilée. Et pour chaque ligne correspondante, il remplacera tout (.*
) entre le début (^
) et fin ($
) de la ligne par la chaîne vide (//
)
5. Suppression des lignes sélectionnées
Dans la section précédente, nous avons modifié la commande de substitution pour effacer certaines lignes de texte. Mais les lignes vides sont restées présentes. Cela est parfois souhaitable. Parfois, ce n'est pas le cas. Dans ce dernier cas, vous voudrez peut-être enquêter sur la suppression commande pour supprimer des lignes entières de la sortie :
# Below, the redirection '> LICENSE' is used to store
# the result of the sed command into the newly
# created LICENSE file:
[email protected]:~$ sed -e 's/<YEAR>/2018/' \
-e 's/<COPYRIGHT HOLDER>/Sylvain Leroux/' \
-e 's/^/# /' \
-e '/----/d' \
MIT.LICENSE > LICENSE
[email protected]:~$ head -5 LICENSE
# Copyright 2018 Sylvain Leroux
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
Le d
est le supprimer nom de la commande. Tout comme les s
était le remplacement nom de la commande. Ici, nous avons spécifié une adresse avant la commande afin que seules les lignes correspondantes soient supprimées (sans aucune adresse, le d
commande aurait supprimé chaque ligne du fichier)
6. Convertir en majuscule
Jusqu'à présent, nous nous sommes principalement concentrés sur le haut du fichier de licence. Mais en effet, il y a des changements que j'aimerais apporter un peu plus loin dans les documents. Voyons d'abord de quoi je parle :
[email protected]:~$ sed -ne '/The above/,$p' LICENSE
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# The software is provided "as is", without warranty of any kind,
# express or implied, including but not limited to the warranties of
# merchantability, fitness for a particular purpose and noninfringement.
# In no event shall the authors or copyright holders be liable for any
# claim, damages or other liability, whether in an action of contract,
# tort or otherwise, arising from, out of or in connection with the
# software or the use or other dealings in the software.
Dans la commande ci-dessus, en utilisant l'option -n, j'ai désactivé l'impression automatique de l'espace du motif. Cela signifie que sed n'imprimera plus rien sur la sortie à moins que je ne lui demande explicitement de le faire. C'est exactement ce que je fais en utilisant la commande print (p). Remarquez qu'au lieu d'utiliser une seule adresse avant la commande p, j'ai utilisé une plage pour afficher le texte entre la ligne contenant le texte "Le dessus" et la fin du document ($).
La commande d'impression peut être utile lorsque vous devez extraire certaines parties d'un fichier. Cependant, pour aujourd'hui, je voulais juste afficher les deux derniers paragraphes pour expliquer ce dont j'ai besoin maintenant :comme c'est une tradition avec les fichiers de licence, je voudrais me couvrir en précisant que le logiciel est fourni "tel quel". Je voudrais donc mettre l'accent sur le dernier paragraphe (commençant par "Le logiciel") en le réécrivant tout en majuscule.
Dans la partie de remplacement d'une commande de substitution, un &est remplacé par le texte correspondant au modèle de recherche. En utilisant l'extension \U GNU, nous pouvons changer la casse de la chaîne de remplacement :
[email protected]:~$ sed -i -e '/The software/,$s/.*/\U&/' LICENSE
[email protected]:~$ cat LICENSE
En clair s/.*/\U&/
signifie "remplacer n'importe quel texte (.*
)par la majuscule (\U
) version de lui-même (&
). Je vous laisse vérifier par vous-même, le dernier paragraphe doit maintenant être écrit en majuscules. Au fait, vous l'avez peut-être remarqué à cause du -i
flag, les modifications ont été appliquées directement au fichier LICENSE.
Nous verrons cela plus en détail dans la section suivante. En attendant, je vous laisse pratiquer et modifier ces commandes à votre guise. Une fois que vous avez un fichier de licence qui correspond à vos goûts, il sera temps de voir comment l'inclure avant chaque fichier source du projet.
7. Insertion d'un fichier texte
Si vous vous attendez à une commande complexe ici, vous serez déçu :insérer un fichier dans un autre est assez simple :
sed -i -e '1r LICENSE' script1.sh
cat script1.sh
Deux choses à voir ici :
- la
r LICENSE
expression est la commande pour lire et insérez un fichier externe dans le fichier en cours de traitement. Il est préfixé ici du chiffre1
qui est une adresse correspondant uniquement à la ligne 1 du fichier d'entrée. - le
-i
l'option permet de changer un fichier en place . Cela signifie que sed créera un fichier temporaire derrière la scène pour y stocker sa sortie et, une fois le traitement terminé, il remplacera le fichier d'origine par le fichier modifié.
Un effet secondaire intéressant de l'option '-i' est que vous pouvez spécifier plusieurs noms de fichiers sur la ligne de commande, et sed appliquera les mêmes transformations à chacun d'eux indépendamment :
sed -i -e '1r LICENSE' *.sh
8. Retour vers le futur
Comme dernier exemple de commande sed, imaginons que quelques années se sont écoulées et que nous sommes maintenant le 1er janvier 2024. L'avis de droit d'auteur de tous les fichiers doit être mis à jour. Il existe plusieurs cas d'utilisation, selon le moment où les fichiers de projet ont été créés. Ainsi, nos avis de droit d'auteur doivent suivre l'un de ces deux formats :
Copyright actuel | Description |
---|---|
Copyright 2023 | Pour les fichiers créés l'année dernière |
Copyright 2018-2023 | Pour les fichiers créés avant l'année dernière |
Nous pouvons capturer ces deux cas d'utilisation à la fois en utilisant une expression régulière étendue (-E). Les seuls éléments "étendus" que nous utiliserons vraiment ici sont les parenthèses :
sed -i -Ee 's/Copyright (....)(-....)?/Copyright \1-2024/' *.sh
Je vous encourage à modifier manuellement l'avis de droit d'auteur dans les fichiers *.sh, puis à exécuter la commande ci-dessus dans différents cas d'utilisation pour voir comment cela fonctionne.
Cela pourrait éventuellement aider votre compréhension si je dis, dans le modèle de recherche :Copyright ::est un texte littéral qui correspondra textuellement; (… .)::définit un groupe de capture correspondant à quatre caractères arbitraires. Espérons que les quatre chiffres d'une année ; (-… .)?: :définit un groupe de capture correspondant à un tiret suivi de quatre caractères arbitraires. Le point d'interrogation à la fin indique que le groupe est facultatif. Il peut ou non être présent dans la ligne d'entrée.
Dans la chaîne de remplacement :Copyright ::est un texte littéral qui sera copié tel quel; \1 ::est le contenu du premier groupe de capture -2024 ::est un texte littéral qui sera copié textuellement.
Si vous avez pris le temps de vérifier la commande par vous-même, cela devrait confirmer si j'applique ces règles aux cas d'utilisation décrits dans le tableau précédent, j'obtiendrai quelque chose comme ça :
Texte correspondant | \1 | \2 | Chaîne de remplacement |
---|---|---|---|
Copyright 2023 | 2023 | Copyright 2023-2024 | |
Copyright 2018-2023 | 2018 | -2023 | Copyright 2018-2024 |
Pour conclure notre guide SED
Nous n'avons fait qu'effleurer la surface ici. Le sed
outil est beaucoup plus puissant que cela. Cependant, même si nous n'avons vu que quatre commandes (s
, p
, d
, et i
) et quelques constructions d'expressions régulières de base (^
, $
, .
, ?
et .*
), vous avez déjà suffisamment de connaissances pour résoudre beaucoup problèmes quotidiens.
Comme j'aime bien terminer un tutoriel par un petit challenge, voici ce que je vous propose :si vous avez téléchargé le support, vous trouverez dans le répertoire du projet un fichier nommé hello.c
. Voici le fichier source d'un programme C de base :
[email protected]:~$ ls
hello.c MIT.LICENSE script1.sh script2.sh
[email protected]:~$ gcc hello.c -o hello
[email protected]:~$ ./hello sylvain
Hello sylvain
[email protected]:~$ cat hello.c
Il y a déjà quelques commentaires dans le fichier source. En les utilisant comme exemples de syntaxe de commentaire dans le langage de programmation C, pourriez-vous insérer la licence MIT dans le hello.c
fichier source à l'aide de la commande sed ? Vous pouvez utiliser une ou plusieurs commandes sed, vous pouvez diriger la sortie d'une commande sed vers une autre, vous pouvez utiliser des fichiers temporaires si vous le souhaitez, mais vous n'êtes pas autorisé à utiliser toute autre commande que sed. Bien sûr, le fichier source C doit toujours être compilé après l'insertion de la licence !
Je vous laisse maintenant réfléchir à ce petit problème, et j'espère que cet article et sa vidéo d'accompagnement vous ont plu. Si vous voulez en savoir plus sur sed, faites-le nous savoir en utilisant la section des commentaires !