- 1. Présentation
- 2. Quelques options
- 3. Utilisation avec le résultat d’une commande.
- 4. Utilisation d’un motif de sélection ou expression rationnelle
- 5. Utilisation d’un motif de substitution
- 6. Restriction des lignes prises en compte
- 7. Fusion de lignes
- 8. Utilisation d’un fichier script
- 9. Substitutions ordonnées à l’aide de sous-expressions (sous-chaînes)
- 10. Quelques exemples pratiques
- 10.1. Insertion d’espaces devant chaque ligne d’un fichier
- 10.2. Modification de tous les fichiers d’un répertoires
- 10.3. Un exemple pris dans le Makefile principal des sources de Debian / Lenny
- 10.4. Exemple du même genre, utilisable à partir du shell courant
- 10.5. Élimination des lignes commençant par le caractère
$
D’après l’édition 11 des travaux d’Alain Leaper, 2018-04-10
Mis à jour le 2020-02-19
Licence GPL
1. Présentation
A partir d’un flux de caractères en entrée, SED réalise un traitement vers un flux de sortie. Le flux d’entrée est issu d’un fichier ou du résultat d’une commande. L’unité de traitement est la ligne (pattern space) (1). Le fichier utilisé en entrée n’est pas modifié (2). Le flux de sortie est dirigé vers le canal de sortie standard (voir memo_7) par défaut l’écran ou, et c’est généralement le cas, redirigé vers un fichier.
Notes:
-
(1) : ce comportement par défaut peut être modifié par l’option
N
, détaillée plus bas -
(2) : ne pas tenter de "rebouclage direct" :
$ sed -e '' <monFier >monFichier
le résultat ne sera pas celui attendu (nomFichier
a toutes les chances d’être vide) !
2. Quelques options
Les options sont introduites par la commande -e
et sont entourées de guillemets ''
(ou ""
).
Une option peut être "vide".
Exemple en utilisant le canal d’entrée standard par défaut (i.e. le clavier) :
$ sed -e '' (1)
salut la compagnie! (2)
salut la compagnie! (3)
(4)
1 | Entrée |
2 | Texte entré au clavier, suivi d’Entrée |
3 | Par défaut, le flux d’entrée est répété sur le canal de sortie |
4 | Ctrl+D pour sortir |
2.1. Option p
(print)
En reprenant le même exemple :
$ sed -e 'p' (1)
salut la compagnie! (2)
salut la compagnie! (3)
salut la compagnie! (4)
(5)
1 | Entrée |
2 | Texte entré au clavier, suivi d’Entrée |
3 | Par défaut, le flux d’entrée est répété sur le canal de sortie |
4 | Impression due à l’option p |
5 | Ctrl+D pour sortir |
2.2. Annulation de la répétition du flux d’entrée: -n
$ sed -n -e 'p' (1)
salut la compagnie! (2)
salut la compagnie! (3)
(4)
1 | Entrée |
2 | Texte entré au clavier, suivi d’Entrée |
3 | Impression due à l’option p , la répétition est supprimée |
4 | Ctrl+D pour sortir |
2.3. Changements sur place : -i
$ sed -i 's/texte_à_remplacer/texte_de_remplacement/g' $nom_du_fichier_cible
Ceci remplace le contenu du fichier en appliquant les transformations directement dans le fichier.
$ sed -i.bak MOTIF $fichier
Et ceci conserve de plus le fichier d’origine dans en conservant le fichier d’origine dans $fichier.bak
.
3. Utilisation avec le résultat d’une commande.
Commande echo pour générer un flux d’entrée.
$ echo -e "salut\ntout le monde" | sed -e 'p'
salut
salut
tout le monde
tout le monde
L’option -e
de echo permet la reconnaissance des fins de ligne (\n
), voir memo_4.
Noter que l’unité de traitement (répétition et impression) est la ligne.
4. Utilisation d’un motif de sélection ou expression rationnelle
Revoir le Memo_7 à ce sujet.
Les caractères /
permettent de délimiter un motif pour réaliser une sélection: /motif/
.
$ echo -e "salut\ntout\nle monde" | sed -n -e '/out/p'
tout (1)
1 | seule le ligne contenant le motif (ici out) est présente en sortie |
4.1. Sortie du numéro de ligne contenant le motif, option =
$ echo -e "salut\ntout\nle monde" | sed -n -e '/out/='
2 (1)
1 | la ligne numéro 2 contient le motif out |
4.2. Négation : "tout sauf le motif" option !
(devant p
ou =
)
$ echo -e "salut\ntout\nle monde" | sed -n -e '/out/!='
1
3 (1)
1 | les lignes 1 et 3 ne contiennent pas le motif |
$ echo -e "salut\ntout\nle monde" | sed -n -e '/out/!p' (1)
salut
le monde
1 | la ligne "tout", qui contient le motif sera éliminée de l’impression |
4.3. Sélection à partir du flux d’entrée, filtrage de la répétition: option d
Ne pas utiliser -n
.
$ echo -e "salut\ntout\nle monde" | sed -e '/out/d'
salut
le monde (1)
1 | la ligne tout, qui contient le motif a été éliminée de la répétition |
On obtient le même résultat qu’avec !p
, mais on ne filtre pas au même niveau…
5. Utilisation d’un motif de substitution
L’option s
par s/motif_1/motif_2
assure le remplacement de motif_1
par motif_2
.
$ echo -e "abzzj\nxxxx\ncdefzz\nghizzzzklm\nvv" | sed -n -e 's/zz/ZZ/p'
abZZj
cdefZZ
ghiZZzzklm (1)
1 | remplacement partiel |
Le remplacement s’effectue pour le premier motif trouvé pour chaque unité de traitement (la ligne).
Pour que toutes les occurrences soient traitées, il faut utiliser l’option g (global)
$ echo -e "abzzj\nxxxx\ncdefzz\nghizzzzklm\nvv" | sed -n -e 's/zz/ZZ/pg'
abZZj
cdefZZ
ghiZZZZklm (1)
1 | remplacement global |
Dans les deux cas, seules les lignes ayant subi une substitution apparaissent en sortie (lignes xxxx et vvv supprimées).
|
De la même manière que la sélection, la substitution peut se faire au niveau du flux d’entrée, sans utiliser -n
et p
.
$ echo -e "abzzj\nxxxx\ncdefzz\nghizzzzklm\nvv" | sed -e 's/zz/ZZ/g'
abZZj
xxxx
cdefZZ
ghiZZZZklm
vv
Les lignes n’ayant pas subi de substitution apparaissent également en sortie (lignes xxxx et vv présentes). C’est généralement le comportement souhaité lorsqu’on effectue des modifications par rapport à un fichier.
|
6. Restriction des lignes prises en compte
Soit le fichier construit selon :
$ echo -e "ozzo\nppzzp\nzzq\nabzzj\nxxzz\ncdefzz\nghizzzzklm\nvvzz\nzz" > fic_1
Si on souhaite limiter le remplacement aux lignes 5 à 8 :
$ sed -e '5,8s/zz/ZZ/g' < fic_1
ozzo
ppzzp
zzq
abzzj (1)
xxZZ
cdefZZ
ghiZZZZklm (2)
vvZZ
zz (3)
1 | les lignes 1 à 4 ne sont pas modifiées |
2 | remplacement pour les lignes 5, 6,7, 8 |
3 | la ligne 9 n’est pas modifiée |
Remarques:
-
$ sed -e '5,+3s/zz/ZZ/g' < fic_1
conduit au même résultat (ligne 5 à ligne 5+3) -
le signe
$
désigne la dernière ligne du fichier :$ sed -e '5,$s/zz/ZZ/g' < fic_1
remplacement à partir de la ligne 5 jusqu’à la fin de fichier
7. Fusion de lignes
L’option N
permet la fusion de plus d’une ligne dans l’unité de traitement.
Soit le fichier construit selon :
$ echo -e "aaa\nbbb\nccc\nddd\neee" > test.txt
7.1. 1er cas : une ligne est réservée puis fusionnée avec l’unité de traitement qui contient la ligne suivante
$ sed -n -e 'N;s/^./X/p' < test.txt
Xaa
bbb
Xcc
ddd
Les 2 lignes se comportent comme une seule, le 1er caractère (début de cette ligne) est modifié. Remarquez que la ligne 5 (eee
) est réservée mais elle ne peut être fusionnée, elle n’est pas traitée.
7.2. 2e cas : une ligne est réservée après celle entrée dans l’unité de traitement
$ sed -n -e 'N;s/^./X/p;N' < test.txt
Xaa
Xcc
Xee
Les 2e (bbb
) et 4e (ddd
) lignes ne sont pas traitées (par rapport à la modification).
7.3. 3e cas : cas hybride (1er cas + 2e cas)
$ sed -n -e 'N;s/^./X/p;N' < test.txt
Xaa
bbb
Xdd
eee
La 3eme ligne (ccc
) est réservée mais non traitée, car vient après celle entrée dans l’unité de traitement.
Autre approche, ne pas utiliser l’option p
(sans -n
, le flux d’entrée est répété sur le canal de sortie).
$ sed -n -e 'N;s/^./X/;N' < test.txt
Xaa
bbb
ccc
Xdd
eee
Un résultat "presque" équivalent (une ligne sur 4 modifiée) peut être obtenu par :
$ sed -n -e 'N;N;s/^./X/' < test.txt
Xaa
bbb
ccc
ddd
eee
Mais il faut "suffisamment" de lignes pour réaliser la fusion !
Avec une ligne de plus (iii
) la fusion ggg
, hhh
, iii
est possible et donc ggg
devient Xgg
.
$ echo -e "aaa\nbbb\nccc\nddd\neee\nfff\nggg\nhhh\niii" > test_2.txt
$ sed -e 'N;N;s/^./X/' < test_2.txt
Xaa
bbb
ccc
Xdd
eee
fff
Xgg
hhh
iii
8. Utilisation d’un fichier script
La commande -f
permet de faire référence à un fichier de commande (script).
Création d’un fichier de commande (cmd_1
) applicable à l’exemple précédent :
$ echo "N;N;s/^./X/" > cmd_1
$ sed -f cmd_1 < test_2.txt
(1)
1 | même résultat que précédemment |
Il est possible d’inclure la partie sed -f
dans le script.
Il faut d’abord trouver son sed
via :
$ whereis sed
sed: /bin/sed
Création du fichier de commande (cmd_2
) :
$ cat > cmd_2 (1)
#!/bin/sed -f (1)
N;N;s/^./X/ (1) (2)
$ chmod u+x cmd_2 (3)
$ cmd_2 <test_3.txt (4)
(5)
1 | Entrée |
2 | Ctrl+D |
3 | Permettre l’exécution |
4 | Le nouveau script est utilisable |
5 | Même résultats que précédemment |
9. Substitutions ordonnées à l’aide de sous-expressions (sous-chaînes)
Re-revoir le Memo_7 à ce sujet.
Ici, dans un motif donné, la sous-expression de rang un est utilisée par la chaîne de remplacement.
$ sed -n -e 's/xxx\(abcd\)zzz/uuu\1tt/p'
xxxabcdzzz
uuuabcdtt
Ensuite, dans un motif donné, les sous-expressione de rangs deux, puis un, sont utilisées par la chaîne de remplacement.
$ sed -n -e 's/xxx\(abcd\)zzz\(efg\)/\2vvv\1tt/p'
kkk xxxabcdzzzefg lmn
kkk efgvvvabcdtt lmn
Autre exemple :
$ sed -n -e 's/\(Dupont \)\(monsieur \)\(Durand \)/\3\2\1/p'
bonjour Dupont monsieur Durand coucou
bonjour Durand monsieur Dupont coucou
10. Quelques exemples pratiques
10.1. Insertion d’espaces devant chaque ligne d’un fichier
$ echo -e "aaa\nbbb\nccc\nddd\neee" > test.txt
$ sed -e 's/\(^.\)/ \1/' < test.txt > provis
$ mv provis test.txt
$ cat test.txt
aaa (1)
bbb
ccc
ddd
eee
1 | 3 espaces en tête de chaque ligne |
Remarques :
-
il est nécessaire d’utiliser un fichier relais (ici
provis
). -
{3}
convient pour une sélection mais pas pour une substitution. Impossible donc de faire :sed -e 's/\(^.\)/ {3}\1/' < test.txt > provis
10.2. Modification de tous les fichiers d’un répertoires
Par exemple, appliquer la même modification que précédemment à tous les fichiers d’extension .txt du répertoire courant vers un sous répertoire.
$ mkdir ./provis
$ for var in *.txt; do sed -e 's/\(^.\)/ \1/' < $var > ./provis/$var; done
$ mv ./provis/* ./ (1)
1 | Si on le souhaite, il ne reste plus qu’à "écraser" les fichiers du répertoire courant |
10.3. Un exemple pris dans le Makefile principal des sources de Debian / Lenny
SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
-e s/arm.*/arm/ -e s/sa110/arm/ \
-e s/s390x/s390/ -e s/parisc64/parisc/ \
-e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
-e s/sh.*/sh/ )
La valeur de la variable SUBARCH
est le résult de la commande uname
(dans un Makefile, précédé de shell
) modifiée par sed
…
10.4. Exemple du même genre, utilisable à partir du shell courant
$ var1=abcd
$ echo $var1
abcd
$ var1=`echo "bonjour"| sed -e 's/abc/efgh/' -e 's/xyz/kk/' -e 's/bonjour/salut/'`
$ echo $var1
salut
10.5. Élimination des lignes commençant par le caractère $
ficOrigine
est supposé contenir des lignes commençant par $
.
$ sed -n -e '/^\$/!p' < ficOrigine > ficSortie