sed: techniques
Mis à jour le 28/09/2023
Attention
Ici, tous les exemples ne modifient pas de fichier car:
Si on n’effectue pas
sed -i
, le résultat est envoyé à la sortie standard.
Avec-i
, le fichier référencé est modifié.
-i
/--in-place
admet le paramètre facultatifSUFFIX
qui permet de créer un fichier backup:
sed --in-place=.bak 's/12/98/' sed-test.txt
créera le fichiersed-test.txt.bak
Divers
- Fonctionne en mode flux pour l’entrée et la sortie. C’est à dire: effectue les traitements ligne par ligne
$
référence la dernière ligne
exemple:sed '$ a # je suis la nouvelle dernière ligne' /etc/hosts
a
ajoute une ligne après celle référencée (ici$
)
ici, on a l’équivalent de la redirection en mode ajout:>>
Dans les exemples qui suivent, le fichier /etc/hosts
contient:
127.0.0.1 localhost
127.0.1.1 hp-cp0318nf
# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
Recherche par regex
-
Ne pas hésiter à lire/relire: Expressions régulières: résumé (la partie Extensions telle que
\d
ne fonctionne pas danssed
) -
On écrit la regex ainsi:
/regex/
- Suppression de toutes les lignes commençant par
#
sed '/^#/d' /etc/hosts
- Recherche entre 2 lignes
Suppression à partir de la ligne qui contient la 1ère regex jusqu’à la ligne qui contient la 2ème regexsed '/^::1/,/^ff02::1/d' /etc/hosts
Fonctionne aussi avec la recherche par numéro de ligne qu’on peut mixer avec la recherche par regex
sed '3,5d' /etc/hosts
Même recherche, en utilisant la valeur relative du numéro de ligne en utilisant
+
sed '3,+2d' /etc/hosts
On peut inverser cette recherche avec
!
:sed '2,5!d' /etc/hosts
Ici, il y a utilisation de la commande de suppression
d
, mais cela marche aussi avec les autres commandes comme le remplacements
Affichage des lignes sur lesquelles la recherche agit
Il faut utiliser l’option -n
et la commande p
de sed
sed -n '/^::1/,/^ff02::1/p' /etc/hosts
-
A utiliser avant de faire des modifications
-
Devient équivalent à
grep -P
Rechercher / Remplacer
La commande s
permet la substitution
sed 's/o/O/'
remplace le 1ero
minuscule de chaque ligne parO
majusculesed 's/o/O/g'
remplace tous leso
minuscule de chaque ligne parO
majusculesed 's/o/O/2'
remplace le 2èmeo
minuscule de chaque ligne parO
majuscule
backref (“Référence arrière”)
Dans le paramètre's/e1/e2/'
e1
et e2
sont des regex
Si
e1
contient des sous-expressions entre parenthèses, on peut les référencer danse2
via leur numéro précédé du caractère\
(l’index va de 1 à 9, au delà, il faut utiliser autre chose quesed
)
Exemple: Remplacer “256” par “512” puis “512” par “1024” dans une ligne (comme dans un fichier de configuration java
)
echo 'des mots -Xms256m -Xmx512m encore des mots' | sed -E 's/(.*Xms)([0-9]+)(.*Xmx)([0-9]+)(.*)$/\1512m\31024m\5/'
Ici il faut mettre
-E
en option desed
, sans celle-ci ça ne marche et je ne sais pas pourquoi !
Lorsque la regex de recherche est unique, on peut utiliser &
pour substituer son expression
echo 'We adopted a cat yesterday. The cat is pretty playful.' | sed 's/cats\?\b/"little &"/g'
Translittération
Concept utilisé par le code César (remplacer des caractères par un autre)
Échanger certains caractères avec d’autres caractères
echo 'échanger des caractères' | sed -re 'y/éèêà/eeea/'
Technique avancé
Supposons que nous ayons un fichier HTML et que nous voulions supprimer les balises pour ne garder que le texte
balises.html
<html
lang="fr"
comment="cette balise est sur plusieurs lignes">
<head>
<title>Test SED</title>
</head>
<body>
<h1>Du contenu pour la page HTML</h1> <h2>Un titre</h2>
<strong><pre>hello world</pre></strong>
</body>
</html>
sed -re 's/<[^>]*>//g' balises.html
est simple mais ne traite pas le cas d’une balise étendue sur plusieurs lignes
sortie de la commande
<html
lang="fr"
comment="cette balise est sur plusieurs lignes">
Test SED
Du contenu pour la page HTML Un titre
hello world
sed -re ':start s/<[^>]*>//g; /</ {N; b start}' balises.html
fonctionne
sortie de la commande
Test SED
Du contenu pour la page HTML Un titre
hello world
Explications
- On va commencer une boucle chaque fois que la regex est détectée
- On déclare une étiquette (pour les anciens comme en assembleur) ->
:start
N
indique qu’il faut insérer la ligne suivante dans le traitement de la ligne en cours/</
est ici comme le test de terminaison de la boucle (mais c’est plus complexe)
Commande pour obtenir le même résultat sans les espaces intempestifs sur chaque ligne (trim) et les lignes vides
sed -re ':start s/<[^>]*>//g; /</ {N; b start}' balises.html|sed '/^$/d'|sed -E 's/^[ ]*(.+)[ ]*$/\1/'
Autre exemple
source https://www.gnu.org/software/sed/manual/html_node/Branching-and-flow-control.html
test.txt
All the wor=
ld's a stag=
e,
And all the=
men and wo=
men merely =
players:
They have t=
heir exits =
and their e=
ntrances;
And one man=
in his tim=
e plays man=
y parts.
sed ':x ; /=$/ { N ; s/=\n//g ; bx }' test.txt