Les bases de l'utilisation de l'éditeur de flux Sed pour manipuler du texte sous Linux
Introduction
La commande sed, abréviation de stream editor, effectue des opérations d'édition sur du texte provenant d'une entrée standard ou d'un fichier. sed édite ligne par ligne et de manière non interactive.
Cela signifie que vous prenez toutes les décisions d'édition lorsque vous appelez la commande, et sed exécute les instructions automatiquement. Cela peut sembler déroutant ou peu intuitif, mais c'est un moyen très puissant et rapide de transformer du texte, en particulier dans le cadre d'un script ou d'un flux de travail automatisé.
Ce didacticiel couvrira certaines opérations de base et vous présentera la syntaxe requise pour faire fonctionner cet éditeur. Vous ne remplacerez certainement jamais votre éditeur de texte habituel par sed, mais il deviendra probablement un ajout bienvenu à votre boîte à outils d'édition de texte.
Remarque : Ce didacticiel utilise la version GNU de sed trouvée sur Ubuntu et d'autres systèmes d'exploitation Linux. Si vous utilisez macOS, vous aurez la version BSD qui a différentes options et arguments. Vous pouvez installer la version GNU de sed avec Homebrew en utilisant brew install gnu-sed.
Utilisation de base
sed fonctionne sur un flux de texte qu'il lit à partir d'un fichier texte ou d'une entrée standard (STDIN). Cela signifie que vous pouvez envoyer la sortie d'une autre commande directement dans sed pour l'éditer, ou vous pouvez travailler sur un fichier que vous avez déjà créé.
Vous devez également savoir que sed affiche tout sur la sortie standard (STDOUT) par défaut. Cela signifie que, à moins d'être redirigé, sed imprimera sa sortie à l'écran au lieu de l'enregistrer dans un fichier.
L'utilisation de base est :
- sed [options] commands [file-to-edit]
Dans ce didacticiel, vous utiliserez une copie de la licence logicielle BSD pour expérimenter sed. Sur Ubuntu, exécutez les commandes suivantes pour copier le fichier de licence BSD dans votre répertoire personnel afin de pouvoir l'utiliser :
- cd
- cp /usr/share/common-licenses/BSD .
Si vous n'avez pas de copie locale de la licence BSD, créez-en une vous-même avec cette commande :
- cat << 'EOF' > BSD
- Copyright (c) The Regents of the University of California.
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. Neither the name of the University nor the names of its contributors
- may be used to endorse or promote products derived from this software
- without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- SUCH DAMAGE.
- EOF
Utilisons sed pour afficher le contenu du fichier de licence BSD. sed envoie ses résultats à l'écran par défaut, ce qui signifie que vous pouvez l'utiliser comme lecteur de fichier en ne lui transmettant aucune commande d'édition. Essayez d'exécuter la commande suivante :
- sed '' BSD
Vous verrez la licence BSD affichée à l'écran :
OutputCopyright (c) The Regents of the University of California.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
...
...
Les guillemets simples contiennent les commandes d'édition que vous transmettez à sed. Dans ce cas, vous ne lui avez rien transmis, donc sed a imprimé chaque ligne qu'il a reçue sur la sortie standard.
sed peut utiliser une entrée standard plutôt qu'un fichier. Canalisez la sortie de la commande cat dans sed pour produire le même résultat :
- cat BSD | sed ''
Vous verrez la sortie du fichier :
OutputCopyright (c) The Regents of the University of California.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
. . .
. . .
Comme vous pouvez le voir, vous pouvez opérer sur des fichiers ou des flux de texte, comme ceux produits lors de la sortie de canalisation avec le caractère pipe (|), tout aussi facilement.
Lignes d'impression
Dans l'exemple précédent, vous avez vu que l'entrée passée dans sed sans aucune opération imprimerait les résultats directement sur la sortie standard.
Explorons la commande explicite print de sed, que vous spécifiez en utilisant le caractère p entre guillemets simples.
Exécutez la commande suivante :
- sed 'p' BSD
Vous verrez chaque ligne du fichier BSD imprimée deux fois :
OutputCopyright (c) The Regents of the University of California.
Copyright (c) The Regents of the University of California.
All rights reserved.
All rights reserved.
Redistribution and use in source and binary forms, with or without
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
modification, are permitted provided that the following conditions
are met:
are met:
. . .
. . .
sed imprime automatiquement chaque ligne par défaut, puis vous lui avez dit d'imprimer les lignes explicitement avec la commande \p, de sorte que chaque ligne est imprimée deux fois.
Si vous examinez attentivement la sortie, vous verrez qu'elle a la première ligne deux fois, suivie de la deuxième ligne deux fois, etc., ce qui vous indique que sed fonctionne sur les données ligne par ligne. Il lit une ligne, opère dessus et sort le texte résultant avant de répéter le processus sur la ligne suivante.
Vous pouvez nettoyer les résultats en passant l'option -n à sed, qui supprime l'impression automatique :
- sed -n 'p' BSD
OutputCopyright (c) The Regents of the University of California.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
. . .
. . .
Nous revenons maintenant à l'impression de chaque ligne une fois.
Les exemples jusqu'à présent peuvent difficilement être considérés comme de l'édition (à moins que vous vouliez imprimer chaque ligne deux fois…). Ensuite, vous explorerez comment sed peut modifier la sortie en ciblant des sections spécifiques des données textuelles.
Utilisation des plages d'adresses
Les adresses vous permettent de cibler des parties spécifiques d'un flux de texte. Vous pouvez spécifier une ligne spécifique ou même une plage de lignes.
Laissons sed imprimer la première ligne du fichier. Exécutez la commande suivante :
- sed -n '1p' BSD
La première ligne s'affiche à l'écran :
OutputCopyright (c) The Regents of the University of California.
En plaçant le nombre 1 avant la commande d'impression, vous avez indiqué à sed le numéro de ligne sur lequel opérer. Vous pouvez tout aussi bien imprimer cinq lignes (n'oubliez pas le \-n) :
- sed -n '1,5p' BSD
Vous verrez cette sortie :
OutputCopyright (c) The Regents of the University of California.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
Vous venez de donner une plage d'adresses à sed. Si vous donnez une adresse à sed, il n'exécutera que les commandes qui suivent sur ces lignes. Dans cet exemple, vous avez demandé à sed d'imprimer les lignes 1 à 5. Vous auriez pu spécifier cela d'une manière différente en donnant la première adresse, puis en utilisant un décalage pour indiquer à sed le nombre de lignes supplémentaires à parcourir, comme ceci :
- sed -n '1,+4p' BSD
Cela se traduira par la même sortie, car vous avez dit à sed de commencer à la ligne 1, puis d'opérer également sur les 4 lignes suivantes.
Si vous souhaitez imprimer une ligne sur deux, spécifiez l'intervalle après le caractère ~. La commande suivante imprime une ligne sur deux dans le fichier BSD, en commençant par la ligne 1 :
- sed -n '1~2p' BSD
Voici la sortie que vous verrez :
OutputCopyright (c) The Regents of the University of California.
modification, are permitted provided that the following conditions
1. Redistributions of source code must retain the above copyright
2. Redistributions in binary form must reproduce the above copyright
documentation and/or other materials provided with the distribution.
may be used to endorse or promote products derived from this software
. . .
. . .
Vous pouvez également utiliser sed pour supprimer du texte de la sortie.
Suppression de texte
Vous pouvez effectuer la suppression de texte là où vous spécifiiez auparavant l'impression de texte en remplaçant la commande p par la commande d.
Dans ce cas, vous n'avez plus besoin de la commande -n car sed imprimera tout ce qui n'est pas supprimé. Cela vous aidera à voir ce qui se passe.
Modifiez la dernière commande de la section précédente pour la rendre
- sed '1~2d' BSD
Le résultat est que vous voyez toutes les lignes qui ne vous ont pas été données la dernière fois :
OutputAll rights reserved.
Redistribution and use in source and binary forms, with or without
are met:
notice, this list of conditions and the following disclaimer.
notice, this list of conditions and the following disclaimer in the
3. Neither the name of the University nor the names of its contributors
without specific prior written permission.
. . .
. . .
Il est important de noter ici que notre fichier source n'est pas affecté. Il est encore intact. Les modifications sont affichées sur notre écran.
Si nous voulons enregistrer nos modifications, nous pouvons rediriger la sortie standard vers un fichier comme celui-ci :
- sed '1~2d' BSD > everyother.txt
Ouvrez maintenant le fichier avec cat :
- cat everyother.txt
Vous voyez la même sortie que vous avez vue à l'écran précédemment :
OutputAll rights reserved.
Redistribution and use in source and binary forms, with or without
are met:
notice, this list of conditions and the following disclaimer.
notice, this list of conditions and the following disclaimer in the
3. Neither the name of the University nor the names of its contributors
without specific prior written permission.
. . .
. . .
La commande sed ne modifie pas le fichier source par défaut, mais vous pouvez modifier ce comportement en passant l'option -i, ce qui signifie \effectuer des modifications sur place. Cela modifiera le fichier source.
Avertissement : L'utilisation du commutateur -i écrasera le fichier d'origine, vous devez donc l'utiliser avec précaution. Effectuez d'abord les opérations sans le commutateur -i, puis exécutez à nouveau la commande avec -i une fois que vous avez ce que vous voulez, créez une sauvegarde du fichier d'origine ou redirigez le sortie dans un fichier. Il est très facile de modifier accidentellement le fichier d'origine avec le commutateur -i.
Essayons en modifiant le fichier everyother.txt que vous venez de créer, sur place. Réduisons davantage le fichier en supprimant toutes les autres lignes
- sed -i '1~2d' everyother.txt
Si vous utilisez cat pour afficher le fichier avec cat everyother.txt, vous verrez que le fichier a été modifié.
L'option -i peut être dangereuse. Heureusement, sed vous donne la possibilité de créer un fichier de sauvegarde avant de le modifier.
Pour créer un fichier de sauvegarde avant de le modifier, ajoutez l'extension de sauvegarde directement après l'option \-i :
- sed -i.bak '1~2d' everyother.txt
Cela crée un fichier de sauvegarde avec l'extension .bak, puis modifie le fichier d'origine sur place.
Ensuite, vous verrez comment utiliser sed pour effectuer des opérations de recherche et de remplacement.
Substitution de texte
L'utilisation la plus connue de sed est peut-être la substitution de texte. sed peut rechercher des modèles de texte à l'aide d'expressions régulières, puis remplacer le texte trouvé par autre chose.
Vous pouvez en savoir plus sur les expressions régulières en suivant l'utilisation d'expressions régulières Grep pour rechercher des modèles de texte sous Linux.
Dans sa forme la plus basique, vous pouvez remplacer un mot par un autre en utilisant la syntaxe suivante :
's/old_word/new_word/'
Le s est la commande de remplacement. Les trois barres obliques (/) sont utilisées pour séparer les différents champs de texte. Vous pouvez utiliser d'autres caractères pour délimiter les champs si cela s'avère plus utile.
Par exemple, si vous essayez de changer le nom d'un site Web, l'utilisation d'un autre délimiteur serait utile car les URL contiennent des barres obliques.
Exécutez la commande suivante pour imprimer une URL avec echo et modifiez-la avec sed, en utilisant le caractère de soulignement (_) comme délimiteur :
- echo "http://www.example.com/index.html" | sed 's_com/index_org/home_'
Cela remplace com/index par org/home. Le résultat affiche l'URL modifiée :
Outputhttp://www.example.org/home.html
N'oubliez pas le délimiteur final, sinon sed se plaindra. Si vous avez exécuté cette commande :
- echo "http://www.example.com/index.html" | sed 's_com/index_org/home'
Vous verriez cette sortie :
Outputsed: -e expression #1, char 20: unterminated `s' command
Créons un nouveau fichier pour pratiquer quelques substitutions. Exécutez la commande suivante pour créer un nouveau fichier texte appelé song.txt :
- echo "this is the song that never ends
- yes, it goes on and on, my friend
- some people started singing it
- not knowing what it was
- and they'll continue singing it forever
- just because..." > song.txt
Remplaçons maintenant l'expression on par forward. Utilisez la commande suivante :
- sed 's/on/forward/' song.txt
La sortie ressemble à ceci :
Outputthis is the sforwardg that never ends
yes, it goes forward and on, my friend
some people started singing it
not knowing what it was
and they'll cforwardtinue singing it forever
just because...
Vous pouvez voir quelques choses remarquables ici. Premièrement, c'est que sed a remplacé les modèles, pas les mots. Le on dans song est remplacé par forward.
L'autre chose à remarquer est qu'à la ligne 2, le deuxième on n'a pas été remplacé par forward.
En effet, par défaut, la commande s fonctionne sur la première correspondance d'une ligne, puis passe à la ligne suivante. Pour que sed remplace chaque instance de on au lieu de la première sur chaque ligne, vous devez passer un indicateur facultatif à la commande de substitution.
Fournissez le drapeau g à la commande de substitution en le plaçant après le jeu de substitution :
- sed 's/on/forward/g' song.txt
Vous verrez cette sortie :
Outputthis is the sforwardg that never ends
yes, it goes forward and forward, my friend
some people started singing it
not knowing what it was
and they'll cforwardtinue singing it forever
just because...
Maintenant, la commande de substitution change chaque instance.
Si vous vouliez uniquement changer la deuxième instance de \on que sed trouve sur chaque ligne, alors vous utiliseriez le nombre 2 au lieu du g :
- sed 's/on/forward/2' song.txt
Cette fois, les autres lignes sont inchangées, car elles n'ont pas de seconde occurrence :
Outputthis is the song that never ends
yes, it goes on and forward, my friend
some people started singing it
not knowing what it was
and they'll continue singing it forever
just because...
Si vous voulez seulement voir quelles lignes ont été remplacées, utilisez à nouveau l'option -n pour supprimer l'impression automatique.
Vous pouvez ensuite passer l'option p à la commande de substitution pour imprimer les lignes où la substitution a eu lieu.
- sed -n 's/on/forward/2p' song.txt
La ligne qui a changé s'affiche à l'écran :
Outputyes, it goes on and forward, my friend
Comme vous pouvez le voir, vous pouvez combiner les drapeaux à la fin de la commande.
Si vous voulez que le processus de recherche ignore la casse, vous pouvez lui passer le drapeau \i.
- sed 's/SINGING/saying/i' song.txt
Voici la sortie que vous verrez :
Outputthis is the song that never ends
yes, it goes on and on, my friend
some people started saying it
not knowing what it was
and they'll continue saying it forever
just because...
Remplacement et référencement du texte correspondant
Si vous souhaitez trouver des modèles plus complexes avec des expressions régulières, vous disposez de plusieurs méthodes différentes pour référencer le modèle correspondant dans le texte de remplacement.
Par exemple, pour faire correspondre le début de la ligne à at, utilisez la commande suivante :
- sed 's/^.*at/REPLACED/' song.txt
Vous verrez cette sortie :
OutputREPLACED never ends
yes, it goes on and on, my friend
some people started singing it
REPLACED it was
and they'll continue singing it forever
just because...
Vous pouvez voir que l'expression générique correspond du début de la ligne à la dernière instance de at.
Puisque vous ne connaissez pas la phrase exacte qui correspondra dans la chaîne de recherche, vous pouvez utiliser le caractère & pour représenter le texte correspondant dans la chaîne de remplacement.
Mettons des parenthèses autour du texte correspondant :
- sed 's/^.*at/(&)/' song.txt
Vous verrez cette sortie :
Output(this is the song that) never ends
yes, it goes on and on, my friend
some people started singing it
(not knowing what) it was
and they'll continue singing it forever
just because...
Une manière plus flexible de référencer du texte correspondant consiste à utiliser des parenthèses d'échappement pour regrouper des sections de texte correspondant.
Chaque groupe de texte de recherche marqué de parenthèses peut être référencé par un numéro de référence échappé. Par exemple, le premier groupe de parenthèses peut être référencé avec \1, le second avec \2 et ainsi de suite.
Dans cet exemple, nous allons échanger les deux premiers mots de chaque ligne :
- sed 's/\([a-zA-Z0-9][a-zA-Z0-9]*\) \([a-zA-Z0-9][a-zA-Z0-9]*\)/\2 \1/' song.txt
Vous verrez cette sortie :
Outputis this the song that never ends
yes, goes it on and on, my friend
people some started singing it
knowing not what it was
they and'll continue singing it forever
because just...
Comme vous pouvez le voir, les résultats ne sont pas parfaits. Par exemple, la deuxième ligne ignore le premier mot car elle contient un caractère non répertorié dans notre jeu de caractères. De même, il traitait theyll comme deux mots dans la cinquième ligne.
Améliorons l'expression régulière pour être plus précise :
- sed 's/\([^ ][^ ]*\) \([^ ][^ ]*\)/\2 \1/' song.txt
Vous verrez cette sortie :
Outputis this the song that never ends
it yes, goes on and on, my friend
people some started singing it
knowing not what it was
they'll and continue singing it forever
because... just
C'est bien mieux que la dernière fois. Cela regroupe la ponctuation avec le mot associé.
Remarquez comment nous répétons l'expression entre parenthèses (une fois sans le caractère *, puis une fois avec). En effet, le caractère * correspond au jeu de caractères qui le précède zéro ou plusieurs fois. Cela signifie que la correspondance avec le caractère générique serait considérée comme une \correspondance même si le modèle n'est pas trouvé.
Pour vous assurer que sed trouve le texte au moins une fois, vous devez le faire correspondre une fois sans le caractère générique avant d'utiliser le caractère générique.
Conclusion
Dans ce didacticiel, vous avez exploré la commande sed. Vous avez imprimé des lignes spécifiques à partir du fichier, recherché du texte, supprimé des lignes, écrasé le fichier d'origine et utilisé des expressions régulières pour remplacer le texte. Vous devriez déjà être en mesure de voir comment transformer rapidement un document texte à l'aide de commandes sed correctement construites.
Dans le prochain article de cette série, vous explorerez certaines fonctionnalités plus avancées.