Base de connaissances CCM
Systèmes d'exploitation - Linux - Shell - Sed




Sujet 4839 - Sed - Supprimer une ou plusieurs lignes d'un fichier

[ Voir ce sujet en ligne ] - [ Catégorie: Systèmes d'exploitation - Linux - Shell - Sed ]


Supprimer une (ou plusieurs) ligne(s) d'un fichier


Syntaxe


sed '{[/]<n>|<chaîne>|<regex>[/]}d' <nom_fichier>
sed '{[/]<adr1>[,<adr2>][/]d' <nom_fichier>

Exemples


Suppression de la 3ème ligne
sed '3d' mon_fichier.txt
Suppression de la ligne contenant la chaîne "awk"
sed '/awk/d' mon_fichier.txt
Suppression de la dernière ligne
sed '$d' mon_fichier.txt
Suppression de toutes les lignes vides
sed '/^$/d' mon_fichier.txt
sed '/./!d' mon_fichier.txt
Suppression de la ligne "matchée" par une expression régulière
(ici on élimine celle contenant des caractères numérique (au moins 1 chiffre) situés en fin de ligne)
sed '/[0-9/][0-9]*$/d' mon_fichier.txt
Suppression de l'intervalle compris entre les lignes 7 et 9
sed '7,9d' mon_fichier.txt
La même chose mais en remplaçant l'adresse par des "motifs"
sed '/-Début/,/-Fin/d' mon_fichier.txt

Note


Les exemples précédents ne font que modifier l'affichage du fichier (sortie standard 1 = l'écran).
Pour des modifications permanentes, pour les anciennes versions (< 4) utiliser un fichier temporaire, pour GNU sed utiliser le paramètre "-i[suffixe]" (--in-place[=suffixe]), comme dans l'exemple suivant :
sed -i".bak" '3d' mon_fichier.txt
qui aura pour effet, de ne produire aucun affichage sur la sortie standard, de modifier le fichier original "mon_fichier.txt" en supprimant la 3ème ligne et de créer un fichier de sauvegarde nommé "mon_fichier.txt.bak".

---------------------------------------------------


Fichier de référence à utiliser pour les exemples (mon_fichier.txt) :
Introduction
Ceci est un exemple de fichier pour se familiariser avec le filtre "sed".

Présentation

-Début-
 Sed est donc un éditeur de flux (Stream EDitor), issu de l'éditeur de texte "ed", très répandu sous les systèmes Unix.
-Fin-

Utilisation

 La commande la plus utilisée du filtre "sed" est sans conteste la commande de substitution (s), qui sert à remplacer dans chaque ligne la première occurence d'une chaîne1 par celle d'une chaîne2.
 Pour une substitution de toutes les occurences (rencontrées) de chaque ligne il faut utiliser le paramètre "g" (global).

Conclusion

 Le filtre "sed" est sans doute une des commandes les plus usitées en association avec d'autres commandes comme "grep" ou "awk" pour l'écriture de scripts shell.
 La connaissance et la maîtrise des expressions régulières est un plus.
 
-------------------
Édité le 05/01/2007
À 17:00 par JP

Lire la suite

Sed - Substitution »
Publié par jipicy - Dernière mise à jour le 18 novembre 2009 à 19:52 par marlalapocket




Sujet 5588 - Sed - Substitution

[ Voir ce sujet en ligne ] - [ Catégorie: Systèmes d'exploitation - Linux - Shell - Sed ]


Substitution




Substitution basique


Simple


- 1ère occurrence (de chaque ligne) rencontrée uniquement
sed 's/la/LA/' fichier.txt

Globale


- Toutes les occurrences (de chaque ligne) rencontrées
sed 's/la/LA/g' fichier.txt

Ciblée


- Seulement la 2ème occurrence (de chaque ligne) rencontrée
sed 's/la/LA/2' fichier.txt

Substitution conditionnée


Simplee


/Motif/ - Uniquement si la ligne contient "motif"
sed '/awk/ s/sed/SED/' fichier.txt

Numéro de ligne - Uniquement la ligne n° "N"
sed '18 s/sed/SED/' fichier.txt

/Regex/ - Uniquement s'il y a correspondance avec l'expression régulière
sed '/^[ ][Ss]ed/ s/ed/ED/g' fichier.txt

Avancée


0,/regex/ - Uniquement la 1ère occurrence rencontrée
sed '0,/sed/ s//SED/' fichier.txt

Bloc


/motif1/,/motif2/ - Uniquement dans l'intervalle "motif1 - motif2"
sed '/Début/,/Fin/ s/ed/ED/' fichier.txt # 1ère occurrence uniquement
sed '/Début/,/Fin/ s/ed/ED/g' fichier.txt # toutes les occurrences

8,13 - Uniquement dans l'intervalle des lignes 8 à 13
sed '8,13 s/ed/ED/g' fichier.txt

On peut aussi combiner motif et ligne
sed '8,/Fin/ s/ed/ED/g' fichier.txt
sed '/Début/,13 s/ed/ED/g' fichier.txt

Ou encore avec des "regex"
sed '/Début/,$ s/ed/ED/g' fichier.txt # jusqu'à la fin ($)
sed '/^[ ][Ss]ed/,13 s/ed/ED/' fichier.txt

Avancéé


Substituer tout un texte entre 2 motifs en excluant les motifs
sed  '/Début/,/Fin/{ /Début/b;/Fin/b; s/.*/SED - The Stream ÉDitor/; }' fichier.txt

----------------------------------------------------------------


Fichier de référence employé pour les exemples : à la fin de cet article

Lire la suite

Sed - Numérotation de lignes »
Publié par jipicy - Dernière mise à jour le 18 novembre 2009 à 15:11 par marlalapocket




Sujet 5589 - Sed - Numérotation de lignes

[ Voir ce sujet en ligne ] - [ Catégorie: Systèmes d'exploitation - Linux - Shell - Sed ]


Numérotation


* Numéroter les lignes (équivalent à "cat -n fichier.txt")

----------------------------------------------------------------


Fichier de référence employé pour les exemples : à la fin de cet article

Lire la suite

Sed - Insérer des espacements »
Publié par jipicy - Dernière mise à jour le 18 novembre 2009 à 19:53 par marlalapocket




Sujet 5590 - Sed - Insérer des espacements

[ Voir ce sujet en ligne ] - [ Catégorie: Systèmes d'exploitation - Linux - Shell - Sed ]


Espacement dans un fichier


* Ajouter une ligne blanche après chaque phrase (ponctuée par un retour chariot) :

----------------------------------------------------------------


Fichier de référence employé pour les exemples : à la fin de cet article

Lire la suite

Sed - Conversion retours chariots DOS (CRLF) / UNIX (LF) »
Publié par jipicy - Dernière mise à jour le 18 novembre 2009 à 19:53 par marlalapocket




Sujet 5978 - Sed - Conversion retours chariots DOS (CRLF) / UNIX (LF)

[ Voir ce sujet en ligne ] - [ Catégorie: Systèmes d'exploitation - Linux - Shell - Sed ]


Conversion format de fichier DOS <> UNIX / UNIX <> DOS




Préambule


Il existe déjà des utilitaires (dos2unix et unix2dos) qui s'acquittent très bien ce cette tâche, mais rien ne vous empêche de vouloir le faire par vous même des fois que le système sur lequel vous travaillez ne possède pas ces outils et que vous soyez dans l'impossibilité de les installer.

Ce qu'il faut savoir


Les fichiers textes sous Unix (et ses descendants) terminent leur ligne par un caractère "saut de ligne", représenté par le symbole "\n" (appelé Line Feed et noté LF, code ASCII = 0A).

Les fichiers texte sous Dos (et ses descendants) terminent eux aussi leur ligne par un caractère "saut de ligne", précédé d'un caractère retour chariot, représenté par le symbole "\r" (appelé Carriage Return et noté CR, code ASCII 0D). Ainsi, chaque ligne d'un fichier DOS se termine par la séquence CRLF, soit \r\n.

Conversion DOS vers UNIX


Il suffit simplement d'effacer le caractère "\r" (retour chariot) de fin de ligne.
Le caractère "\r" (retour chariot) est représenté symboliquement par "^M", qui s'obtient par la séquence de touches suivante "CTRL-V" + "CTRL-M".
sed 's/^M$//' fichier

Note :

Avec la version GNU-sed (gsed 3.02.80 et supérieur), on peut utiliser la notation ASCII :
sed 's/\x0D$//' fichier

Conversion UNIX vers DOS


Il suffit de faire le contraire de la commande précédente, à savoir (le caractère "^M" étant saisit de la même façon (CTRL-V + CTRL-M)) :
sed 's/$/^M/' fichier

Note :

Avec la version GNU-sed (gsed 3.02.80 et supérieur), on peut utiliser la notation symbolique "\r":
sed 's/$/\r/' fichier

Lire la suite

Sed - Mettre la première lettre d'un mot en majuscule »
Publié par jipicy - Dernière mise à jour le 18 novembre 2009 à 16:54 par marlalapocket




Sujet 6007 - Sed - Mettre la première lettre d'un mot en majuscule

[ Voir ce sujet en ligne ] - [ Catégorie: Systèmes d'exploitation - Linux - Shell - Sed ]


Capitaliser la 1ère lettre d'un mot (ou d'une phrase)


Gsed 4.0 et supérieur
sed 's/^./\u&/'
Exemples :
$ echo "bonjour la vie" | sed 's/^./\u&/'
Bonjour la vie

$ echo -e "bonjour la vie\net bonjour à toi" | sed 's/^./\u&/'
Bonjour la vie
Et bonjour à toi

$

Lire la suite

Sed - Mettre la première lettre de chaque mot en majuscule »
Publié par jipicy - Dernière mise à jour le 18 novembre 2009 à 19:22 par marlalapocket




Sujet 6008 - Sed - Mettre la première lettre de chaque mot en majuscule

[ Voir ce sujet en ligne ] - [ Catégorie: Systèmes d'exploitation - Linux - Shell - Sed ]


Capitaliser la 1ère lettre de chaque mot


Voici deux façons de procéder :
Exemples :
$ echo -e "bonjour la vie." | sed -r 's/(^.| .)/\U&/g'
Bonjour La Vie.

$ echo -e "bonjour la vie\net bonjour à toi" | sed -r 's/(^.| .)/\U&/g'
ou
$ echo -e "bonjour la vie\net bonjour à toi" | sed -r 's/(\b.)/\U&/g'
Bonjour La Vie
Et Bonjour À Toi

$ echo -e "bonjour la vie." | sed 's/^.\| [a-z]/\U&/g'
Bonjour La Vie.

$ echo -e "bonjour la vie\net bonjour à toi" | sed 's/^.\| [a-z]/\U&/g'
Bonjour La Vie
Et Bonjour À Toi

$ 


Note : - les 2 premières méthodes ne fonctionnent que si et seulement il y un seul espace entre les mots.
Voici l'amélioration de la 1ère méthode pour que ça marche sans tenir compte de nombre d'espaces entre les mots.
sed -r 's/(^.|[ ]+.)/\U&/g'

Lire la suite

Sed - Insérer un espace entre chaque lettre »
Publié par jipicy - Dernière mise à jour le 17 novembre 2009 à 19:04 par marlalapocket




Sujet 6009 - Sed - Insérer un espace entre chaque lettre

[ Voir ce sujet en ligne ] - [ Catégorie: Systèmes d'exploitation - Linux - Shell - Sed ]


Insérer un espace entre chaque lettre


$ echo -e "bonjour la vie\net bonjour à toi" | sed 's/./& /g'
b o n j o u r   l a   v i e
e t   b o n j o u r   à   t o i
L'inconvénient c'est que l'espace naturel entre chaque mot est doublé. Pour pallier à ce petit désagrément il suffit d'ajouter :
$ echo -e "bonjour la vie\net bonjour à toi" | sed 's/./& /g;s/  / /g'
b o n j o u r  l a  v i e
e t  b o n j o u r  à  t o i
$  

Voici encore une variante. Par rapport à la précédente le remplacement et fait dans un seul coup de s///
$ echo -e "bonjour la vie\net bonjour à toi" | sed -r 's/([^ ])/\1 /g'
b o n j o u r  l a  v i e
e t  b o n j o u r  à  t o i

Pour ne pas utiliser l'option -r on peut écrire
 sed 's/\([^ ]\)/\1 /g'

Classe de caractères complémentée [^...]


[^...] - est une classe de caractères complémentée qui signifie "reconnaître un caractère non énuméré" et non "ne pas reconnaître un caractère énuméré".
Dans notre cas on peut traduire "reconnaître un caractère qui n'est pas espace".

Lire la suite

Sed - Insertion de texte »
Publié par jipicy - Dernière mise à jour le 18 novembre 2009 à 19:15 par marlalapocket




Sujet 6616 - Sed - Insertion de texte

[ Voir ce sujet en ligne ] - [ Catégorie: Systèmes d'exploitation - Linux - Shell - Sed ]


Insérer du texte dans un fichier




Introduction


Il est parfois utile de pouvoir insérer du texte en en-tête d'un ou plusieurs document(s), ou dans une partie bien précise du document (avant ou après telle ou telle ligne).
L'éditeur de flux "sed" peut nous aider dans cette tâche et nous allons voir comment.

Syntaxe


Quel que soit la méthode (insertion, ajout ou échange), la syntaxe reste la même, à savoir :
sed '{/motif/|/regexp/|n}{i|a|c}\<Texte à insérer>' fichier

Ajout de texte


Il existe trois façons d'insérer du texte dans un document :

Insérer une ligne avec "i"


La syntaxe est très simple, il suffit de désigner la ligne avant laquelle doit être insérée notre nouvelle ligne, soit par son numéro correspondant, soit par un motif. Dans le cas d'un motif une ligne sera insérée avant chaque ligne comportant ledit motif.

Exemple :
sed "16i\Notes : La négation s'obtient avec un point d'exclamation ! \n " fichier.txt

sed "/Conclusion/i\Notes : La négation s'obtient avec un point d'exclamation ! \n" fichier.txt

Ajouter une ligne avec "a"


La syntaxe est toujours aussi simple, il suffit de désigner la ligne après laquelle doit être insérée notre nouvelle ligne, soit par son numéro correspondant, soit par un motif. Dans le cas d'un motif une ligne sera insérée après chaque ligne comportant ledit motif.

Exemple :
sed "8a \"ed\" est un éditeur de texte orienté ligne. Il est utilsé pour créer, afficher\
, modifier ou encore manipuler des fichiers textes." fichier.txt

sed "/\"ed\"/a \"ed\" est un éditeur de texte orienté ligne. Il est utilsé pour créer, afficher\
, modifier ou encore manipuler des fichiers textes." fichier.txt

Échanger une ligne avec "c"


La syntaxe reste toujours la même, il suffit de désigner la ligne devant être substituée par notre nouvelle ligne, soit par son numéro correspondant, soit par un motif. Dans le cas d'un motif chaque ligne comportant ledit motif sera substituée par la nouvelle ligne.

Exemple :
sed "/14/c Divers paramètres peuvent être passer en fin d'expression, comme par exemple le paramètre \"g\" (pour global), pour une substitution globale de chaque occurrence" fichier.txt

sed "/global/c Divers paramètres peuvent être passer en fin d'expression, comme par exemple le paramètre \"g\" (pour global), pour une substitution globale de chaque occurrence" fichier.txt

----------------------------------------------------------------


Fichier de référence employé pour les exemples : à la fin de cet article

Lire la suite

Sed - Trucs et astuces »
Publié par jipicy - Dernière mise à jour le 18 novembre 2009 à 15:29 par marlalapocket




Sujet 6699 - Sed - Trucs et astuces

[ Voir ce sujet en ligne ] - [ Catégorie: Systèmes d'exploitation - Linux - Shell - Sed ]



Substitution


Affichage


Suppression


Espace et tabulation


Ligne vide


Intervalle régulier


Divers


Joindre des lignes


Affichage insensible à la casse


(Afficher uniquement les lignes correspondant à un motif donné avec insensibilité à la casse)

Cette astuce fait suite à cette discussion sur le forum Linux/Unix

La commande "sed" possède bien un "flag" - voir Sed - Introduction à SED - Part I - permettant de mettre en correspondance un motif sans tenir compte de la casse, mais ce flag ne s'applique qu'à la seule commande de substitution (commande s) malheureusement.

Voilà donc une astuce permettant de se servir de ce flag pour afficher (ou au contraire ne pas afficher) des lignes correspondant à un motif donné sans tenir compte de sa casse.
Il suffit pour cela d'employer la commande de substitution "s" combinée au métacaractère "&" et bien sur du flag "I".

Exemple pour n'afficher que les lignes contenant le terme "motif" (ou Motif, MOTIF, mOtIf, MoTiF, etc)


À compléter...

Lire la suite

Sed - Introduction à SED - Part I »
Publié par jipicy - Dernière mise à jour le 5 novembre 2009 à 20:11 par marlalapocket




Sujet 9536 - Sed - Introduction à SED - Part I

[ Voir ce sujet en ligne ] - [ Catégorie: Systèmes d'exploitation - Linux - Shell - Sed ]


SED - The Stream EDitor - Part I


Ce document est une introduction à la pratique et à l'utilisation de l'éditeur de flux "SED", qui essaie de couvrir certaines fonctionnalités assez méconnues, pour ne pas dire "quasi inconnues", qui font de "SED" un outil indispensable dans la boîte à outils de tout Linuxien désireux de se rompre aux maniements et aux arcanes du traitement de fichiers via une console et un shell.

Sommaire part I







Partie II
Partie III

Présentation


Sed signifie "Stream EDitor" autrement dit "éditeur de flux", et plus précisément "éditeur de flux orienté ligne". De par sa conception et son mode de fonctionnement, Sed est un éditeur non-interactif.

Tout comme l'éditeur "ed" -dont il est issu et que l'on trouve toujours dans les distributions actuelles- et contrairement aux autres éditeurs tels que vi, emacs, Nedit, Xedit, etc., qui eux fonctionnent sur une page complète de texte affiché à l'écran, Sed agit sur une seule ligne à la fois.

À ses débuts l'éditeur "ed" s'est vu doté d'une commande travaillant sur son flux d'entrée standard plutôt que sur un fichier, capable d'afficher toutes les lignes contenant une expression régulière. Cette commande dont la syntaxe s'écrit sous la forme "g/re/p" (global/regular expression/print) donnera naissance à l'utilitaire "grep". Quelques temps après une nouvelle implémentation d'une version de "ed" vit le jour, travaillant uniquement sur le flux d'entrée standard tout en tirant ses instructions d'un fichier de scripts. Cette version fut baptisée Stream EDitor, plus connue sous le nom de "Sed".

L'éditeur de flux Sed lit les lignes d'un ou plusieurs fichiers depuis l'entrée standard, enchaine des commandes lues elles aussi depuis l'entrée standard sous forme d'expressions (commandes d'édition) ou depuis un fichier texte (script), et écrit le résultat du traitement sur la sortie standard.

On pourrait résumer le mécanisme de fonctionnement de Sed de cette façon :

Notons que pour sélectionner la ou les ligne(s) sur la(les)quelle(s) elles doivent opérer, les commandes acceptent des numéros de lignes, des intervalles, ou encore des expressions régulières (notées RE ou regex).

Introduction


Sed prend ses instructions (commandes) depuis la ligne de commandes ou depuis un fichier (script) et applique chaque instruction, dans l'ordre de leur apparition, à chaque ligne en entrée. Une fois que chaque instruction a été appliquée à la 1ère ligne d'entrée, la ligne est affichée (ou non, selon ses besoins) sur la sortie standard (l'écran, ou redirigée dans un fichier) et Sed procède alors à la lecture et au traitement de la ligne suivante et ainsi de suite jusqu'à la fin du fichier d'entrée (à moins qu'il ne rencontre une instruction de sortie explicite).
Ce mécanisme est appelé "cycle". On entend par cycle le traitement des données présentes dans l'espace de travail par l'ensemble des commandes qui composent le script. Par défaut un cycle correspond à :

Essayons d'illustrer à l'aide d'un organigramme le fonctionnement de Sed à travers un script tout simple qui efface les lignes vides d'un fichier et celles ne comportant qu'un seul caractère "dièse" (#) en début de ligne. Pour ce faire voici un exemple de fichier comportant pour la circonstance quelques lignes vides, quelques dièses seuls dont un en retrait et non pas en début de ligne et deux lignes avec plusieurs dièses à la suite :.

Le fichier :
#
#
 #
##
# Ceci est un commentaire

# En voici un autre
#

#
#
###
# Et un autre


#

#
# Et un dernier pour la route
#
Le script en lui même est relativement simple. Le voici sur une seule ligne :
sed -e '/^$/d;/^#$/d'

et dans un fichier script :
#! /bin/sed -f

/^$/d			# on efface les lignes vides
/^#$/d	# on efface les lignes ne comportant qu'un seul caractère "dièse"
        			#+ se trouvant en début de ligne et rien d'autre derrière
Et l'organigramme :

Syntaxe


Syntaxe générale


sed [-options] [commande] [<fichier(s)>]
sed [-n [-e commande] [-f script] [-i[.extension]] [l [cesure]] rsu] [<commande>] [<fichier(s)>]

Syntaxe d'une commande


L'adressage d'une ou plusieurs lignes par quelques moyens que ce soit est facultatif pour n'importe quelle commande
[adresse[,adresse]][!]commande[arguments]

Par contre un ensemble de commandes peuvent être appliquées à une ligne ou intervalle de lignes en les entourant par des accolades.
[adresse[,adresse]]{
commande1
commande2
commande3
}

Notez que ces commandes peuvent être accolées sur une seule ligne à condition d'être séparées par un point virgule (;).
[adresse[,adresse]]{commande1; commande2; commande3}

Adressage


Sed peut adresser directement une ligne (ou un intervalle) par son numéro de ligne ou par la mise en correspondance avec une expression régulière ciblant un motif (patron/modèle) défini.

Un point d'exclamation (!) après un numéro de ligne, un motif ou une expression régulière exclura cette ligne (ou intervalle) du traitement à effectuer.

Cet adressage peut s'effectuer sous les formes suivantes :

num
début~pas
$
/exp/
\#exp#
num1,num2
/exp1/,/exp2/
num,/exp/
/exp/,num

Les options (paramètres)


Sed accepte des options (paramètres) en entrée, peu nombreuses, et dont les plus usitées sont "-n", "-e" et "-i".


-n, --quiet, --silent
-e script, --expression=script
-f fichier-script, *--file=fichier-script
-i[SUFFIXE], --in-place[=SUFFIXE]
--posix
-r, --regexp-extended
-s, --separate
-u, --unbuffered
--help
--version

Les commandes


Nous allons voir dans les chapitres qui suivent les commandes utilisées par Sed. Autant certaines d'entre-elles peuvent paraitre simples d'utilisation et communes dans leur ensemble, autant pour quelques autres, peu connues il est vrai, leur utilisation et implémentation au sein de scripts Sed peuvent s'avérer plus difficile au point de vue syntaxe et mise en œuvre, mais donner une autre dimension à cet outil relégué au rang de simple filtre...

Certaines commandes admettent un adressage multi-lignes (intervalle) alors que d'autres ne tolèrent qu'une seule adresse voir même aucune pour une minorité. Ces particularités seront notifiées pour chaque commande.

Les commandes basiques 1


Sont regroupées dans ce chapitre les commandes les plus connues de l'éditeur Sed et relativement simples d'emploi.

#
Commentaire (Aucune adresse autorisée)

Si les deux premiers caractères d'un script sed sont "#n", l'option "-n" (no-autoprint) est alors forcée. Donc si votre script doit impérativement débuter par une ligne de commentaire commençant par la lettre "n" minuscule, veillez à utiliser un "N" majuscule ou d'insérer un espace entre le dièse (#) et le "n".

q quit
quitter (une adresse autorisée)
d delete
effacer (intervalle d'adresse autorisée)
p print
affichage (intervalle d'adresse autorisée)
n next-line
ligne suivante (intervalle d'adresse autorisée)
{ ... }
commandes groupées (intervalle d'adresse autorisée)
s substitution
La commande de substitution (intervalle d'adresse autorisée)

Pour interpréter littéralement une esperluette (&) ou un anti-slash (\) il faut les préfixer par un anti-slash :
\& ou \\

flags


Les drapeaux ou attributs

La commande de substitution (s) peut être suivie d'aucun ou de plusieurs drapeaux/attributs (flags en anglais). Certaines combinaisons ne peuvent être associées comme l'attribut "g" (global) et une nième occurrence (N) ce qui relèverait d'une incohérence absolue. Dans le même ordre d'idée, l'attribut "w" doit être le dernier de la liste.

g global
	echo "AAAAA" | sed 's/A/B/'
	BAAAA
	echo "AAAAA" | sed 's/A/B/g'
	BBBBB

N nième occurrence
	echo "AAAAA" | sed 's/A/B/3'
	AABAA

p print (affichage)
	$ var="ligne1\nligne2\nligne3\nligne4\nligne5"
	$ echo -e "$var"
	ligne1
	ligne2
	ligne3
	ligne4
	ligne5

	$ echo -e "$var" | sed '3 s/e3/e n° 3/'
	ligne1
	ligne2
	ligne n° 3
	ligne4
	ligne5

	$ echo -e "$var" | sed -n '3 s/e3/e n° 3/'

	$ echo -e "$var" | sed '3 s/e3/e n° 3/p'
	ligne1
	ligne2
	ligne n° 3
	ligne n° 3
	ligne4
	ligne5

	$ echo -e "$var" | sed -n '3 s/e3/e n° 3/p'
	ligne n° 3


w fichier - Write (écriture dans un fichier)
	
	$ var="ligne1\nligne2\nligne3\nligne4\nligne5"
	$ echo -e "$var" | sed -n '3 s/e3/e n° 3/pw fich.out'

e evaluate (évaluation)

Exemple 1 :
	$ echo $var
	ligne1\nligne2\nligne3\nligne4\nligne5\nligne6\nligne7\nligne8\nligne9
	$ echo $A
	Bonjour
	$ echo -e "$var" | sed 's/.*5/echo '$A'/e'
	ligne1
	ligne2
	ligne3
	ligne4
	Bonjour
	ligne6
	ligne7
	ligne8
	ligne9
	$

Exemple 2 :
	$ cat plop
	0x00000000 0          root      777
	0x00000000 65537      user1  600
	0x00000000 98306      user1  600
	
	$ echo -e "$var" | sed 's/.*5/cat plop/e'
	ligne1
	ligne2
	ligne3
	ligne4
	0x00000000 0          root      777
	0x00000000 65537      user1  600
	0x00000000 98306      user1  600
	ligne6
	ligne7
	ligne8
	ligne9
	$  
Discussion en rapport sur le forum

I case-Insensitive
	
	$ echo "BonJouR" | sed 's/bONjOUr/Salut/'
	BonJouR
	
	$ echo "BonJouR" | sed 's/bONjOUr/Salut/I'
	Salut

M

Pour essayer de faire plus simple, en tant normal l'espace de travail contient une ligne lue en entrée. D'autres lignes peuvent être ajoutées à l'espace de travail à travers l'emploi des commandes comme N, G, x, etc. Toutes ces lignes dans l'espace de travail sont séparées par le caractère de fin de ligne "\n" mais sont vues par Sed comme une seule et même ligne dont le début commence avant la 1ère ligne et se terminant à la fin de la dernière ligne. Avec le flag "M" chaque caractère représentant le début (^) et la fin ($) de ligne reprend si on peut dire ainsi, son sens initial et fait correspondre le début et la fin de ligne à chaque ligne se trouvant dans l'espace de travail.

Voici un exemple illustrant l'emploi du flag "M" :

1er cas :
	$ echo -e "foo\nbar" | sed 'N;s/^.*$//'
	$

Dans ce 1er cas, ^ et $ pointent le début et la fin du tampon qui après l'application de la commande "N" contient "foo\nbar$", et l'expression régulière matche donc tout ce qui se trouve entre les deux caractères symbolisant le début (^) et la fin ($) sans tenir compte du caractère représentant la fin de ligne "\n"

2ème cas :
	$ echo -e "foo\nbar" | sed 'N;s/^.*$//M'
	bar
	$


Dans ce 2nd cas, ^ et $ pointent le début et la fin de la 1ère ligne dans le tampon, qui comme précédemment après l'application de la commande "N" contient "foo\nbar$", mais à la différence que l'expression régulière matche uniquement les caractères se trouvant avant le caractère fin de ligne "\n"

3ème cas :
	$ echo -e "foo\nbar\nfoobar\nbarfoo" | sed -e ':boucle; N; $! b boucle; s/^.*$//M3'
	foo
	bar
	
	barfoo
	$

Dans ce 3ème cas, le tampons après l'exécution de la commande "N" (à l'intérieur d'une boucle ayant pour effet de charger l'intégralité des lignes dans le tampon), ressemble à "foo\nbar\nfoobar\nbarfoo$" et la substitution ne s'applique qu'à la 3 ème ligne matérialisée par le caractère "\n".

Voici 2 autres exemples :

Le 1er :
	$  echo -e "foo\nfoo\nfoo\nbar\nfoo" |  sed 'N;/bar$/s/^/>/Mg;P;D'
	foo
	foo
	>foo
	>bar
	foo
	$

Dans l'exemple ci-dessus, 2 lignes sont chargées dans l'espace de travail, si la fin du tampon ne finit pas par "bar", alors la 1ère ligne du tampon est affichée (P), puis effacée (D), et on reprend l'exécution du script avec le chargement de la ligne suivante (à la suite de celle restant dans le tampon) où l'on vérifie à nouveau la mise en correspondance avec l'expression régulière. Si la correspondance est établie, on ajoute un chevron (>) en début de ligne, à la suite de quoi la 1ère ligne du tampon est affichée (P), puis effacée (D) et on reprend l'exécution du script...

Le 2nd :
	$ echo -e "foo\nfoo" |  sed 'N;s/^/>/;s/\n/\n>/g'
	>foo
	>foo
	
	$ echo -e "foo\nfoo" |  sed 'N;s/^/>/Mg'
	>foo
	>foo
	$

Dans cet exemple on s'emploie à démontrer l'utilité du flag "M" en n'utilisant qu'une seule expression pour rajouter un chevron en début de chaque ligne contenue dans l'espace de travail après l'appel de la commande "N".

Les commandes basiques 2


y
Transposition de caractères
(intervalle d'adresse autorisée)
L'emploi le plus courant pour cette commande est sans nul doute le remplacement des caractères accentués si cher à notre bonne langue française. En voici un petit exemple :
	
	sed '
	y/àâéèêëîïôöùûü/aaeeeeiioouuu/
	y/ÀÂÉÈÊËÎÏÔÖÙÛÜ/AAEEEEIIOOUUU/
	' fichier.txt

a\
text
Ajout
(une adresse autorisée)
	sed '/Ligne n° 5/ a\
	Bonjour
	' fich.txt

i\
text
Insertion
(une adresse autorisée)
	sed '/Ligne n° 4/ i\
	Bonjour
	' fich.txt

c\
text
Échange
(intervalle d'adresse autorisée)
	sed '/Ligne n° 2/,/Ligne n° 6/ c\
	Annulé\
	Pour cause\
	de travaux
	' fich.txt


r fichier read
Lecture
(une adresse autorisée)
Vous pouvez vous en servir pour, par exemple, rajouter une signature en bas d'une série de fichiers. Pour illustrer ces propos, nous allons rajouter le contenu du fichier "signature.txt" à la fin de tous les fichiers correspondant au motif "fich*.txt" (observez bien l'exemple qui suit et remarquez l'emploi du switch "-s". Amusez-vous à l'enlevez et notez la différence d'affichage) :
	sed -s '$ r signature.txt' fich*.txt


w fichier write
Écrire
(une adresse autorisée)
Si le fichier n'existe pas il sera créé, même si le traitement est nul en sortie (aucune écriture envoyée)
Voici un petit scénario pour mettre cette commande en application. Depuis un fichier "adresses.txt" regroupant des noms de distributions associés à un code postal et sa ville de référence, extraire le nom de la distribution et sa ville associé et et l'envoyée dans un nouveau fichier portant le nom du département. Ce script nommé "foo.sed" sera appelé de la façon suivante :
sed -f foo.sed < adresses.txt

Contenu du fichier "foo.sed" :
	#n

	/\b31/{
	s/[0-9][0-9]*//
	w Haute-Garonne
	}
	/\b34/{
	s/[0-9][0-9]*//
	w Hérault
	}
	/\b66/{
	s/[0-9][0-9]*//
	w Pyrénées-Orientales
	}


=
	sed -n '/motif/=' fichier

l [N] --line-length=N
Césure
(intervalle d'adresse autorisée)
	sed -n l fichier	# affichage caractères non imprimable
	sed -n 'l 8' fichier	# idem mais avec un retour à la ligne tous les 8 caractères

Les commandes avancées


Outre les commandes que nous venons de voir, Sed possède bien d'autres commandes, certes peu utilisées car moins bien connues et pour certaines pas très facile à assimiler et à mettre en application, mais qui lui permettent de pouvoir s'acquitter de certaines tâches sans avoir à pâlir de son simple statut d'outil ou de simple filtre.

Les commandes précédentes utilisées principalement le mécanisme suivant :
lecture d'une ligne du fichier d'entrée dans l'espace de travail à laquelle est appliquée chaque commande du script séquentiellement. Lorsque la fin du script est atteinte,, la ligne est alors envoyée sur la sortie standard, l'espace de travail est effacé, une nouvelle ligne est lue en entrée et le contrôle est passée à nouveau au début du script.

Avec les commandes qui suivent, nous allons voir comment inter-agir sur le déroulement du script, modifier le flux d'entrée sous certaines conditions, stocker des parties de lignes, tester des conditions, etc. etc...

Ces commandes peuvent se décomposer en 3 groupes :

Les commandes multi-lignes


N Next
Suivant
(intervalle d'adresse autorisée)
L'exemple qui suit cherche une ligne contenant le motif "C". Si celle-ci est trouvée, il ajoute la ligne suivante dans l'espace de travail et substitue le caractère fin de ligne "\n" pas un tiret entouré d'un espace de chaque côté :
echo -e "A\nB\nC\nD\nE" | sed  '/C/{N;s/\n/ - /}'


D Delete
Effacer
(intervalle d'adresse autorisée)
Pour illustrer l'emploi de la commande "D", je vais prendre un exemple donné dans l'excellent livre publié chez O'Reilly (sed & awk, Second Edition) et qui résume très bien le mécanisme de cette commande à l'instar de la commande "d".

Le fichier de référence (commande_D.txt) :
Cette ligne est suivie d'une ligne vide

Cette ligne est suivie de 2 lignes vides


Cette ligne est suivie de 3 lignes vides



Cette ligne est suivie de 4 lignes vides



Fin du fichier

Pour des raisons de mises en page inhérentes à cet FAQ, dans le fichier ci-dessus, il n'y a que 3 lignes vides en dessous de la ligne "Cette ligne est suivie de 4 lignes vides". Pensez à rajouter une 4ème ligne lors de vos essais avant d'expérimenter cet exemple.

Le but étant de regrouper les lignes vides consécutives en une seule. La commande "d" semble toute appropiée à cette tâche. Voyons un 1er script utilisant cette commande :
sed '
/^$/{
N
/^\n$/d
}' commande_D.txt

Pour se faire nous allons employer un motif nous permettant de matcher une ligne vide "/^$/". Dès qu'une ligne vide est trouvée nous demandons alors le chargement de la ligne suivante dans l'espace de travail avec la commande "N". Une fois cette ligne chargée, nous vérifions alors que le motif présent dans l'espace de travail correspond bien au motif "/^\n$/" (un saut de ligne en tout et pour tout), et si c'est le cas, nous l'effaçons (commande "d"). Mais voilà, cette syntaxe ne marche que pour le cas ou le nombre de lignes est impair. Ceci s'explique par le fait que la commande "d" efface l'intégralité du contenu de l'espace de travail.
Effectivement, dès qu'une ligne vide est trouvée la ligne suivante est chargée (N), si cette ligne est vide, l'espace de travail est effacé (d) et un nouveau cycle est commencé avec une nouvelle ligne. Ainsi si cette nouvelle ligne (3ème) est vide, et la suivante non, alors la commande d'effacement (d) n'est pas appliquée et la ligne vide est affichée.

Par contre si nous remplaçons la commande "d" par son homologue "D" de cette façon :
sed '
/^$/{
N
/^\n$/D
}' commande_D.txt

Nous obtenons le résultat escompté. En effet, la commande "D" n'efface que la partie de l'espace de travail comprise avant le 1er caractère "/n" (saut de ligne), de ce fait si 2 lignes vides se retrouvent dans l'espace de travail, seule la 1ère ligne est effacée et le script redémarre avec le contenu de l'espace de travail (une ligne vide), une nouvelle ligne est alors chargée, si elle n'est pas vide, les 2 lignes contenues dans l'espace de travail sont alors envoyées vers la sortie standard, sinon la 1ère partie est effacée et le scénario est répété...

En d'autres mots, si deux lignes vident se retrouvent dans l'espace de travail, seule la 1ère est effacée, si c'est une ligne vide suivie de texte, elles sont envoyées sur la sortie standard.

P Print
Affichage
(intervalle d'adresse autorisée)

Les mémoires tampons


L'éditeur de flux Sed dispose de deux mémoires tampons qui permettent de stocker la (les) ligne(s) en cours de traitement.

Ces mémoires tampons sont souvent référencées sous l'appelation de "pattern space" pour la mémoire principale, que l'on pourrait traduire par "espace de modèle" ou encore "espace de travail", et par "hold space" pour la mémoire secondaire, traduisible par "espace annexe".

L'espace de travail (pattern space) est l'espace mémoire où sont maintenues les données (la ou les ligne(s)) sélectionnées pendant leur durée de traitement.

L'espace annexe (hold space) est l'espace mémoire où les données (la ou les ligne(s)) peuvent être stockées temporairement.

Les commandes permettant de jongler entre ces deux espaces sont au nombre de cinq.
En voici un bref résumé :

À part la commande "x", les autres commandes marchent pour ainsi dire par paires et agissent pour chaque binome à la manière des redirections (>, >>, <,<<) des interpréteurs de commandes dans les shell comme "bash" ou "ksh". Leur rôle pourrait se traduire de cette façon :

Voici une définition plus succinte de chaque commande pouvant affecter l'espace de travail :

h hold pattern space
espace de modèle annexe
(intervalle d'adresse autorisée)

H Hold pattern space
espace de modèle annexe
(intervalle d'adresse autorisée)

g get contents
copie le contenu
(intervalle d'adresse autorisée)

G Get contents
ajoute le contenu
(intervalle d'adresse autorisée)

x eXchange
échange
(intervalle d'adresse autorisée)

Vous trouverez à la fin de ce documents quelques exemles commentés sur l'emploi des mémoires tampons de "sed", et pour commencer un petit exemple tout simple (toujours tiré de l'ouvrage des Éditions O'Reilly), très facile à comprendre, mais qui nous met en garde sur une des erreurs parfois incompréhensible qui peut arriver et nous faire tourner en bourrique ;-))

Une de ces erreurs justement concerne la mémoire annexe. Lorsque nous envoyons le contenu de l'espace de travail, et que nous procédons à divers traitements, et que ces traitements ne restituent le contenu de la mémoire annexe que sous certaines conditions, il peut arriver que ce contenu ne soit jamais restitué dans l'espace de travail et de ce fait, jamais envoyé vers la sortie standard...

En voici la démonstration.
Nous allons afficher la variable suivante :
$ A="1\n2\n11\n22\n111\n222"
$ echo -e "$A"
1
2
11
22
111
222


et demandé à "sed" d'intervertir les lignes commençant par "1" avec celles commençant par "2".

Pour ce faire nous allons commencer par matcher les lignes commençant par "1", copier le contenu dans la mémoire annexe avec la commande "h", puis vider l'espace de travail, c'est le rôle de la commande "d". À ce moment là, le contrôle est renvoyée au début du script, où une nouvelle ligne est chargée (avec un "2"), la 1ère compraison (/1/) échoue, mais la seconde (/2/) est vraie, donc le contenu de la mémoire annexe est ajoutée à l'espace de travail, qui contient alors "2\n1$". Comme nous sommes arrivés à la fin du script, le contenu de l'espace de travail est affiché et remplacé par l'entrée suivante (11) et le script recommence, et ainsi de suite...

Voilà le script :
echo -e "$A" | sed '
/1/{		# si le motif est présent
h		# le copier dans la mémoire annexe
d		# effacer le contenu de la mémoire principale
}
/2/{		# si le motif est présent
G		# ajouter le contenu de la mémoire annexe
}'


et l'affichage final :
2
1
22
11
222
111


Comme nous l'avons vu, tout se passe bien dans le meilleur des mondes. Mais qu'en serait-il si nous glissons un "333" à la place du "22" ? Et bien justement c'est ce qu nous allons voir.
Tout d'abord, l'affichage de la nouvelle variable :
$ A="1\n2\n11\n33\n111\n222"
$ echo -e "$A"
1
2
11
33
111
222


Et son passage à la moulinette par "sed" :
$ echo -e "$A" | sed '/1/{h;d};/2/{G}'
2
1
33
222
111


Et bien comme vous pouvez le voir, l'affichage du "11" est passée à la trappe ! Et pourquoi donc ? Et bien, comme cela a été dit en début de cet exemple, tout bonnement parce que le contenu de la mémoire annexe n'est restitué dans l'espace de travail que si et seulement si un motif contenant un "2" est rencontré. Dans le cas contraire, le script continue son bohnomme de chemin, autrement dit, il affiche la ligne présente dans l'espace de travail (33) et passe le contrôle au début du script qui charge la ligne suivante (111), ligne qui satisfait la condition du 1er motif (/1/) et de ce pas envoie son contenu dans l'espace annexe, écrasant de ce fait les données présentes (11).

Donc, attention lors de l'élaboration de certains scripts de bien restituer le contenu de la mémoire annexe.

Étiquettes


Les étiquettes (label) permettent de sauter à un emplacement précis à l'intérieur même d'un script. Sed possède trois commandes prévues à cet effet. Une commande inconditonnelle "b" comme "branchement" et deux commandes conditionnelles "t" et "T" comme "[tT]est".

La syntaxe pour désigner une étiquette se limite à placer en début de ligne (pour un script) deux points suivis d'une lettre (ou suite de lettres afin de former un mot, cette dernière étant vivement recommandée pour une meilleure lisibilité du code).

:etiquette


Cette étiquette sera alors appelée dans le script à l'aide des commandes "b", "t" ou "T".tout simplement en faisant précédée son nom par la commande désirée :

b etiquette
t etiquette
T etiquette

Branchement inconditionnel


b branch
(intervalle d'adresse autorisée)
Exemple de branchement inconditionnel

Branchement conditionnel


t test
(intervalle d'adresse autorisée)
Exemple de branchement conditionnel 1

T test
(intervalle d'adresse autorisée)
Exemple de branchement conditionnel 2

SED - The Stream EDitor - Part II


Suite Part II => SED - The Stream EDitor - Part II

Lire la suite

Sed - Introduction à SED - Part III »
Publié par jipicy - Dernière mise à jour le 16 novembre 2009 à 16:40 par marlalapocket




Sujet 9558 - Sed - Introduction à SED - Part III

[ Voir ce sujet en ligne ] - [ Catégorie: Systèmes d'exploitation - Linux - Shell - Sed ]


SED - The Stream EDitor - Part III


Ce document est une introduction à la pratique et à l'utilisation de l'éditeur de flux "SED", qui essaie de couvrir certaines fonctionnalités assez méconnues, pour ne pas dire "quasi inconnues", qui font de "SED" un outil indispensable dans la boîte à outils de tout Linuxien désireux de se rompre aux maniements et aux arcanes du traitement de fichiers via une console et un shell.

Sommaire part III







Partie I
Partie II

Les exemples


Substitutions


nième occurence


1ère occurrence :
$ echo "azerty azerty azerty" | sed 's/az/qw/'
qwerty azerty azerty

2ème occurrence :
$ echo "azerty azerty azerty" | sed 's/az/qw/2'
azerty qwerty azerty

3ème occurrence :
$ echo "azerty azerty azerty" | sed 's/az/qw/3'
azerty azerty qwerty

Toutes les occurrences :
$ echo "azerty azerty azerty" | sed 's/az/qw/g'
qwerty qwerty qwerty

Substituer les fins de lignes par un espace


sed '
:s		# étiquette
N		# on ajoute la ligne suivante
s/\n/ /		# on substitue les fins de lignes par un espace
b s		# on se branche à l'étiquette
'
Sur une ligne :
sed ':s;N;s/\n/ /;bs'

Afficher un intervalle entre 2 motifs sans les motifs


sed -n '/foo/,/bar/{//d;p}' fichier
sed -n '/Mandriva/,/RedHat/{//d;p}' adresses.txt

Gourmandise des expressions régulières


$ echo "azerty azerty azerty" | sed 's/a.*z/qw/'
qwerty

$ echo "azerty azerty azerty" | sed 's/a[^a]*z/qw/'
qwerty azerty azerty

La commande "n"


Localiser une ligne par un motif (/222/), charger la ligne suivante dans l'espace de travail et substituer la 2ème occurrence du chiffre "3" par un "4" :
$ echo -e "111\n222\n333\n444" | sed  '/222/{n; s/3/4/2}'
111
222
343
444

En n'affichant que la ligne concernée sur la sortie standard :
$ echo -e "111\n222\n333\n444" | sed -n '/222/{n; s/3/4/2p}'
343

Le même avec des lettres :
$ echo -e "AAA\nBBB\nCCC\nDDD" | sed '/BBB/ {n;s/C/Z/2}'
AAA
BBB
CZC
DDD

Indentation du script avec "sedsed" et explications sommaires :
$ echo -e "AAA\nBBB\nCCC\nDDD" | sedsed -i '/BBB/ {n;s/C/Z/2}'
/BBB/ {		# On sélectionne la ligne avec ce motif 
    n		# On place la ligne suivante dans l'espace de travail
    s/C/Z/2	# On remplace le 2nd C par un Z
}


Il va de soit que ces 2 exemples ne sont là que pour une simple démonstration et ne sont pas du tout optimisés ni adaptés en ce qui concerne les substitutions, qui auraient pu (du) être faites en ciblant directement la ligne concernée.

Inverser 2 lignes


sed '
6 {	# sélection de la ligne
h	# copie dans la mémoire annexe
N	# ajout dans la mémoire principale de la ligne suivante
G	# ajout du contenu de la mémoire annexe à la mémoire principale
	#+ la mémoire principale contenant à ce moment là :
	#++ Ligne n° 6\nLigne n°7\nLigne n° 6\n
D	# effacement jusqu'au 1er caractère de fin de ligne (\n)
}
'

Sur une ligne :
sed '6 {h;N;G;D}'

Effacement d'une ligne et insertion plus loin


#! /bin/sed -f

1 h		# chargement 1ère ligne mémoire secondaire
1 d		# effacement 1ère ligne
5 { 		# sélectionner sur la ligne 5
G		# ajouter le contenu de la mémoire secondaire à la mémoire principale
N		# ajouter la ligne suivante (la 6)
s/\n/ /g	# substituer tous les sauts de ligne (\n) par un espace
}

Sur une seule ligne :
sed -n '1 h; 1 d; 5 { G; N; s/\n/ /g};P' fich.txt 

Dissocier les commentaires des commandes


Passer toutes les lignes de commentaires se trouvant sur la même ligne que la commande associée, sur une ligne seule au-dessus de la commande :
sed '
/^#\|^$/! {		# Exclure les lignes débutant par un dièse et les lignes vides
/#/ {			# Si la ligne contient un dièse
h			# La copier dans l'espace annexe. L'original est encore dans l'espace de travail
s/.*\(#.*\)/\1/		# Ne conserver que ce qui se trouve après le dièse (dièse compris)
x			# Échanger l'espace de travail avec l'espace annexe
s/\(.*\)#.*/\1/		# Ne conserver que ce qui se trouve avant le dièse
x			# Échanger l'espace de travail avec l'espace annexe
G			# Ajouter le contenu de l'espace annexe à l'espace de travail
}
}
' prog.sed

Sur une seule ligne :
sed '/^#\|^$/!{/#/{h; s/.*\(#.*\)/\1/;x;s/\(.*\)#.*/\1/;x;G;}};' prog.sed

Affichage conditionné


Afficher une ligne de commentaire uniquement si la ligne précédente est vide
sed -n '
/^$/ {
n
/^#/p
}
' fich2.txt

Sur une seule ligne :
sed -n '/^$/{n;/^#/p}' fich2.txt

Émulation de grep


Exemple 1


Émulation de : grep -A3 -B5 "motif" fichier

#!/bin/sh

# Émulation de grep -A3 -B5 "motif" fichier
# Largement inspiré du script grep4.sh
# sur le site : http://www.grymoire.com/Unix/Sed.html#uh-56

case "$#" in
        1) ;;

*) echo "Usage: $0 \motif\" < fichier";exit;;
esac;

sed -n '
'/$1/' !{
        # Motif non satisfait - ajouter la ligne dans la mémoire annexe
        H
        # Remettez-le dans la mémoire principale (espace de travail)
        x
        # Ne conserver que 3 lignes dans le tampon
        # 2 lignes correspondent à .*\n.*
        # 3 lignes à  .*\n.*\n.*
        # On efface les lignes excédentaires
        s/^.*\n\(.*\n.*\n.*\)$/\1/
        # Mettre les 3 lignes (au plus) dans la mémoire annexe à nouveau
        x
}
'/$1/' {
        # Le motif est satisfait - Ajouter le contenu de la mémoire principale
        # à la mémoire secondaire
        H
        # Prendre la ligne suivante (n) et ajouter les 4 autres (N)
        n;N;N;N;N
        # Ajouter le tout à la mémoire annexe
        H
        # Échanger le tout avec la mémoire principale
        x
        # Afficher les lignes
        p
}'

Sur une seule ligne :
sed -n '/ERROR/! {H;x;s/^.*\n\(.*\n.*\n.*\)$/\1/;x;}; /ERROR/ {H;n;N;N;N;N;H;x;p}'

Exemple 2 - Commande "x"


Voici 2 manières de faire pour émuler "grep -A1 -B1" (juste afficher la ligne précédente et la ligne suivante d'une ligne contenant un motif), en utilisant dans un 1er temps juste un échange entre les 2 mémoires tampons avec la commande "x" et dans un 2nd temps l'emploi de copie et d'ajout avec les commandes "h" et "H" combinées à la commande "x".

Commande "x"
#! /bin/bash

sed -n '	# affichage sur demande uniquement
/indice7/! {	# motif absent
x		# on place la ligne dans la mémoire annexe (en fait on échange le contenu)
d		# on efface l'espace de travail
}
/indice7/ {	# motif présent
x		# on l'échange avec le contenu de la mémoire annexe qui contient la ligne précédente
p		# on l'affiche
x		# on échange à nouveau la contenu des 2 mémoires
p		# on affiche la ligne contenant le motif
n		# on charge la ligne suivante
p		# on l'affiche
x		# on la replace dans la mémoire annexe
}
' fich3.txt

Sur une seule ligne :
sed -n '/indice7/! {x;d;}; /indice7/{x;p;x;p;n;p;x;}' fich3.txt

Exemple 3 - Commandes "h" "H" "x"


#! /bin/bash

sed -n '	# affichage sur demande uniquement
/indice7/! {	# motif absent
h		# on garde la ligne dans la mémoire annexe
}
/indice7/{	# motif présent
H		# on l'ajoute au contenu de la mémoire annexe
n		# on charge la ligne suivante
H		# on l'ajoute au contenu de la mémoire annexe
x		# on échange le contenu des 2 mémoires
p		# on l'affiche
}
' fich3.txt

Sur une seule ligne :
sed -n '/indice7/! {h;}; /indice7/{H;n;H;x;p;}' fich3.txt

Étiquettes, boucles et mémoires tampons


Soit le fichier suivant (fich3.txt) :
Regrouper sur une seule et même ligne, la ligne contenant "motif" et les lignes suivantes ne comportant pas ce motif.
#! /bin/sed -f

:notag		# étiquette "pas de motif"
/tag/!{		# si la ligne ne contient pas le motif
1!H		# ajouter le contenu à la mémoire annexe, sauf la 1ère ligne
1h		# copie la 1ère ligne dans la mémoire annexe
x		# échanger le contenu des 2 mémoires tampons
s/\n/ /g	# supprimer tous les caractères de nouvelle ligne (\n)
x		# échanger à nouveau le contenu des 2 mémoires tampons
$b lastline	# se brancher à l'étiquette "dernière ligne"
d		# effacer le contenu de l'espace de travail
}
/tag/{		# si la ligne contient le motif
x		# échanger le contenu des 2 mémoires tampons
/^$/!p		# si la ligne n'est pas vide, l'afficher
$b lastline	# se brancher à l'étiquette "dernière ligne"
d		# effacer le contenu de l'espace de travail
b notag		# se brancher à l'étiquette "pas de motif"
}
:lastline	# étiquette "dernière ligne"
x		# échanger le contenu des 2 mémoires tampons
p		# afficher le contenu de l'espace de travail

Sur une seule ligne :

sed -n ':notag;/tag/!{1!H;1h;x;s/\n/ /g;x;$b lastline;d;};/tag/{x;/^$/!p;$b lastline;d;b notag;};:lastline;x;p;'

Supprimer deux lignes précédents un motif donné


Supprimer les deux lignes précédents un motif donné.

Le fichier de référence : plop
Pattern
blablabla
blablabla
blu
ToDelete << Ligne à effacer
ToDelete << Ligne à effacer
Pattern
blablabla
blablabla
blo
ToDelete << Ligne à effacer
ToDelete << Ligne à effacer
Pattern
blablabla
blablabla
bly
ToDelete << Ligne à effacer
ToDelete << Ligne à effacer
Pattern
blablabla
blablabla


La commande :
sed '
/Pattern/ !{			# La ligne ne contient pas le motif
    :z				# Étiquette
    h				# On copie l'espace de travail dans la 
    				#+ dans la mémoire annexe
    N				# On ajoute la ligne suivante
    /Pattern$/ !b z		# L'espace de travail ne se termine pas par
    				#+ le motif recherché 
    				#++ alors on se branche à l'étiquette
    s/.*\n//			# La ligne se termine par le motif, on
    				#+ supprime tout jusqu'au dernier caractère 
    				#++ représentant un saut de ligne
    x				# On échange le contenu des 2 mémoires
    s/\(.*\)\n.*\n.*$/\1/	# On efface les 2 dernières lignes
    G				# On ajoute le contenu de la mémoire annexe
    				#+ à l'espace de travail
}' plop


Le thread en rapport dans le forum

Effacer les n dernières lignes


Éliminer les n dernières lignes sans connaitre le nombre de lignes (ici les 4 dernières)
seq 10 |	# on génère 10 lignes à partir de la commande "seq"
sed -n '	# affichage sur demande uniquement
:s		# étiquette
1,3 {		# tant qu'on n'a pas 3 lignes dans l'espace de travail
N		# on ajoute la ligne suivante
b s		# on se branche à l'étiquette jusqu'à remplir la condition
}
4,$ {		# tant qu'on n'a pas atteint la dernière ligne
N		# on ajoute la ligne suivante
P		# on affiche la ligne contenue dans l'espace de travail jusqu'au 1er caractère
		#+ symbolisant une fin de ligne (\n)
D		# puis on l'efface de l'espace de travail
}
'

Sur une seule ligne :
seq 10 | sed  -n ':s;1,3{N;bs};4,${N;P;D}'

Émulation de "tac" (inverser les lignes d'un fichier)


#!/bin/sed -nf

# Hormis la 1ère ligne
1!G     # A jouter le contenu de la mémoire annexe à l'espace de travail

# Si la dernière ligne est atteinte
$p      # Afficher le résultat

# Copier le contenu de l'espace de travail dans la mémoire annexe
h

Sur une seule ligne :
sed -n '1! G;$ p;h' 

Exemple de branchement inconditionnel


Remplacer toutes les fins de ligne par des tirets
sed -e '
:boucle		# étiquette
N				# on ajoute la ligne suivante
$! b boucle	# tant que la dernière ligne n'est pas atteinte 
				#+ on se branche à l'étiquette
s/\n/--/g		# on substitue toutes les fins de ligne par 2 tirets (--)
' fich.txt

Sur une seule ligne :
sed -e ':boucle;N;$! b boucle; s/\n/--/g'

Exemple de branchement conditionnel (t)


(si une substitution a été opérée, alors on boucle)
Centrer du texte sur 20 colonnes en ajoutant un espace avant et après
sed -e '
:boucle			# étiquette
s/^.\{1,20\}$/ & /	# on substitue le contenu de la ligne par lui même (&) en ajoutant
			#+ un espace avant et après
t boucle		# tant qu'une substitution a eu lieu, se brancher à l'étiquette
' fich.txt

# Sur une seule ligne :
#
sed -e ':boucle;s/^.\{1,20\}$/ & /; t boucle'

Autre exemple de branchement conditionnel


Transformer "AABBCCDDEEFF" en "AA:BB:CC:DD:EE:FF"

On serait tenté d'utiliser un simple :
echo "AABBCCDDEEFF" | sed 's/../&:/g'

Mais le problème c'est que cette syntaxe rajoute aussi un ":" en fin de ligne :
AA:BB:CC:DD:EE:FF:


La solution consiste donc à faire une boucle en utilisant la syntaxe des expressions régulières et notamment les limites de caractère ou de mot (word boundary) :
echo "AABBCCDDEEFF" | sed ':z;s/\<..\B/&:/;tz'

Exemple de branchement conditionnel (T)


(si une substitution n'a pas été opérée, alors on boucle)
Éliminer un intervale de lignes dont le début est représenté par un motif (C) et la fin étant le 3ème "Y".
$ var="A\nY\nB\nY\nC\nY\nD\nY\nE\nY\nF\nG"

echo -e "$var" |\
sed '
/C/ {
    :boucle
    N
    s/.*Y.*Y.*Y//
    T boucle
}
'

Sur une seule ligne :
sed  '/C/{:boucle;N;s/.*Y.*Y.*Y//;T boucle};'



Pour la portabilité utiliser plutôt :

sed '
/C/ {
    :boucle
    N
    s/.*Y.*Y.*Y//
    t
    b boucle
}
'

Sur une seule ligne :
sed -e '/C/{:boucle' -e 'N;s/.*Y.*Y.*Y//;t' -e 'b boucle' -e '}'


# Voir aussi cette discussion dans le forum :
http://www.commentcamarche.net/forum/affich 4856842 sed substitution

sed '			# recherche le motif /* ... */
s!/\*.*\*/!!		# sur une ligne
/;[ ]*\/\*/ {		# sur plusieurs lignes mais ne commençant pas en début de ligne (après
			#+ un point virgule suivi éventuellement d'un (ou plusieurs) espace(s)
    :z			# étiquette pour boucler
    N			# on ajoute la ligne suivante
    s!/\*.*\*/!!	# on suprime tout entre /* et */
    T z			# on teste si une substitution a eu lieu. Dans le cas contraire on boucle
}
/\/\*/,/\*\// d		# sur plusieurs lignes
'

Substitution avec tampons


Substitution des 2 premières occurrences d'une expression en employant les tampons
echo $A
2007:10:07 16:34:05

echo $A |
sed -e '
h			# on copie l'espace de travail dans la mémoire annexe
s/\(.*\) .*/\1/		# on ne garde que la 1ère partie de l'expression (la date)
s/:/-/g			# on substitue tous les deux points par des tirets
x			# on échange le contenu des 2 mémoires
s/.*\( .*\)/\1/		# on ne garde que la 2nd partie de l'expression (l'heure)
H			# on l'ajoute au contenu de la mémoire annexe
g			# on copie le contenu de la mémoire annexe dans l'espace de travail
s/\n//			# on supprime le caractère fin de ligne
'

Sur une seule ligne :
echo $A |sed -e 'h;s/\(.*\) .*/\1/;s/:/-/g;x;s/.*\( .*\)/\1/;H;g;s/\n//'

Décommenter les directives d'un fichier


Soit un fichier de configuration avec ses directives, ses lignes de commentaires et ses instructions commentées. Chaque paragraphe étant séparé du suivant par une ligne vide.
Comment décommenter un jeu d'instructions qui commence par une ligne commentée (contenant un mot-clé) suivie par les directives commentées elles aussi.
sed '
/# mot-clé/ {		# motif recherché
:label			# étiquette
/^$/q			# si la ligne est vide on quitte
n			# on charge dans l'espace de travail la ligne suivante
s/^#//			# on supprime le dièse en début de ligne
t label			# si une substitution a eu lieu, on se branche à l'étiquette
}
' fichier

Sur une seule ligne :
sed '/# mot-clé/{:label;/^$/q;n;s/^#//;t label;}'

Conversion de caractères


Convertir seulement les 12 premiers caractères accentués de chaque ligne :
$ cat plop
àaéeèeôoùuïiàaéeèeôoùuïiàaéeèeôoùuïiàaéeèeôoùuïié
ÀaéeÈeôoùuïiàaéeèeôoùuïiàaéeèeôoùuïiàaéeèeôoùuïié
àaéeèeôoùuïiàaéeèeôoùuïiàaéeèeôoùuïiàaéeèeôoùuïié
àaéeèeÔoùuïiàaéeèeôoùuïiàaéeèeôoùuïiàaéeèeôoùuïié
àaÉeèeôoùuïiàaéeèeôoùuïiàaéeèeôoùuïiàaéeèeôoùuïié


sed '
h					# on copie l'espace de travail dans la mémoire annexe
s/\(^.\{12\}\).*/\1/			# on récupère les 12 premiers caractères de l'espace de travail
y/àâéèêëîïôöùûü/aaeeeeiioouuu/		# on convertit les minuscules
y/ÀÂÉÈÊËÎÏÔÖÙÛÜ/AAEEEEIIOOUUU/		# on convertit les majuscules
x					# on échange le contenu des 2 mémoires
s/^.\{12\}\(.*\)/\1/			# on récupère tous les caractères après le 12 ème 
x					# on échange le contenu des 2 mémoires
G					# on ajoute le contenu de la mémoire annexe
s/\n//					# on supprime les caractères fin de ligne
' plop

Mise en forme de texte 1


Voici un exemple illustrant avec 2 méthodes bien différentes, la mise en forme d'un texte selon les critères suivants :
à partir de la 6ème virgule, supprimer chaque guillemet encadrant chaque champ, exepté le dernier

Le texte de référence :
$ cat plop
{"88","6","Trademark2","Model6","6OD","7","false","null","null","1","30","1","40","1","60","1","65","1","65","1","70","1","70","1","70"},
{"89","6","Trademark2","Model6","6PD","7","false","null","null","10","30","10","50","10","70","15","75","25","75","25","80","25","80","25","80"},

Avec boucle conditionnée


Méthode avec une boucle conditionnée :

sed '
s/,/,\n/5		# On substitue la 5 ème virgule par elle même
			#+ suivie d'un saut de ligne 
:s			# étiquette
s/\(\n.*\)"/\1/		# là on joue sur la gourmandise des regex, la
			#+ sous-expression englobant tout ce qui se trouve
			#++ avant le dernier guillemet que l'on remplace donc
			#+++ par elle même à l'exception du guillemet
t s			# tant qu'une substitution a eu lieu, on boucle
s/\n\(.*\)}/"\1"}/	# et pour finir on remplace tout ce qui se trouve
			#+ après le saut de ligne jusqu'à l'accolade fermante
			#++ par ce contenu plus un guillemet et une accolade
			#+++ la virgule finale n'étant pas dans la LHS est
			#++++ reportée naturellement
'
plop

Sur une seule ligne :
sed 's/,/,\n/5;:s;s/\(\n.*\)"/\1/;ts;s/\n\(.*\)}/"\1"}/'

Avec mémoire tampon


Méthode avec mémoire tampon :

sed '
s/\"/§/12	# on substitue le 12 ème guillemet par un caractère quelconque
h		# on copie la mémoire principale dans la mémoire annexe
s/§.*//		# on efface ce caractère et tout qui se trouve après
x		# on échange le contenu des 2 mémoires
s/.*§,//	# on efface la partie correspondante à la mémoire annexe
s/\"//g		# on supprime tous les guillemets
x		# on échange à nouveau le contenu des 2 mémoires
G		# on ajoute le contenu de la mémoire annexe à la principale
s/\n/,/		# on remplace le saut de ligne séparant les 2 mémoires par
		#+ une virgule
s/}/\"}/	# on rajoute le dernier guillemet
'
plop

Sur une seule ligne :
sed -e 'h;s/\"/§/12;s/§.*//;x;s/\"/§/12;s/.*§,//;s/\"//g;x;G;s/\n/,/;s/}/\"}/' plop

Mise en forme de texte 2


Dans le même esprit que précédemment, mais ici il faut remplacer les espaces vides contenus au début du 1er champ (et uniquement dans celui-ci) par des 0 (zéros).
2 méthodes là encore, une avec boucle et une utilisant les mémoires tampons.

Fichier de référence :
$ cat plop
 1023 LOGS blabla
12333 LOGS blabla
   44 LOGS blabla
 2580 LOGS blabla
 1458 LOGS blabla
    5 LOGS blabla

Méthode avec boucle



sed '
/^ / {				# seules les lignes commençant par un espace
    :boucle			# étiquette
    s/^ [^[:alnum:]]*/&\n/	# on ajoute un saut de ligne après le dernier espace du 1er champ
    s/\([ ]\?\) \{1\}\n/\10/	# on substitue un espace par lui même suivi d'un 0 (zéro)
    t boucle			# tant qu'une substitution a eu lieu, on boucle
}
'

Sur une seule ligne :
sed '/^ / {:boucle; s/^ [^[:alnum:]]*/&\n/; s/\([ ]\?\) \{1\}\n/\10/; t boucle}' plop

Méthode avec mémoires tampons



sed '
/^ / {				# seules les lignes commençant par un espace
    s/^ [^[:alnum:]]*/&\n/	# on ajoute un saut de ligne après le dernier espace du 1er champ
    h				# on copie la mémoire principale dans la mémoire annexe
    s/\n.*$//			# on efface de la mémoire principale tout ce qui suit le saut de
    				#+ ligne (saut de ligne compris)
    s/ /0/g			# on substitue tous les espaces par des 0 (zéros)
    x				# on échange le contenu des 2 mémoires
    s/.*\n//			# on efface cette fois ci tout ce qui précède le saut de ligne 
				#+ (saut de ligne compris)
    x				# on échange à nouveau le contenu des 2 mémoires
    G				# on copie le contenu de la mémoire annexe à la suite de la
    				#+ mémoire principale
    s/\n//			# et on supprime le saut de ligne
}
'

Sur une seule ligne :
sed '/^ / {s/^ [^[:alnum:]]*/&\n/;h;s/\n.*$//;s/ /0/g;x;s/.*\n//;x;G;s/\n//}' plop

Post en référence

La commande "c"


echo -e "A\nB\nC\nD\nE\nF\nG" | sed '/B/,/F/ c\DELETED'

Les fichiers de références pour les exemples


Vous trouverez ci-dessous la plupart des fichiers utilsés tout au long de ce document pour illustrer les différents exemples vus, afin de vous permettre de mieux cerner certaines commandes.

fich.txt



Ligne n° 1
Ligne n° 2
Ligne n° 3
Ligne n° 4
Ligne n° 5
Ligne n° 6
Ligne n° 7
Ligne n° 8
Ligne n° 9
Ligne n° 10

fich2.txt



Ligne n° 1
Ligne n° 2
# commentaire1 # Ligne n° 3
Ligne n° 4
Ligne n° 5 # La prochaine ligne est vide (6)

# commentaire2 # Ligne n° 7, la ligne précédente est vide (6)
Ligne n° 8
Ligne n° 9 # La prochaine ligne est vide (11)

Ligne n° 11 # La ligne précédente est vide (10)
Ligne n° 12
Ligne n° 13
Ligne n° 14

fich3.txt



Ligne n° 1 tag :
indice1 indice2
indice3
Ligne n° 2 tag :
Ligne n° 3 tag :
Ligne n° 4 tag :
indice4 indice5
Ligne n° 5 tag :
Ligne n° 6 tag:
indice6
Ligne n° 7 tag :
Ligne n° 8 tag :
indice7
indice8 indice9
indice10
Ligne n° 9 tag :
Ligne n° 10 tag :

adresses.txt



Ubuntu		31000	Toulouse
Mandriva	34000	Montpellier
SuSE		66000	Perpignan
Debian		31130	Balma
Gentoo		34500	Béziers
Slackware	66100	Collioure
Fedora		31400	Muret
RedHat		34200	Agde
Kaella		66500	Elne

signature.txt



-- 
Pour toutes correspondances, veuillez vous adressez à :
(substituez "<moderateur>" par le nom du modérateur adéquat)
<moderateur>@commentcamarche.com
Merci de votre attention.
L'équipe CCM

prog.sed



#! /bin/sed -f


1 h		# chargement 1ère ligne mémoire secondaire
1 d		# effacement 1ère ligne
5 { 		# sélectionner sur la ligne 5
G		# ajouter le contenu de la mémoire secondaire à la mémoire principale
N		# ajouter la ligne suivante (la 6)
s/\n/ /g	# substituer tous les sauts de ligne (\n) par un espace 
}

# Sur une seule ligne :
# sed -n '1 h; 1 d; 5 { G; N; s/\n/ /g};P' fich.txt

Discussions en rapport sur le forum

Lire la suite

Sed - Introduction à SED - Part II »
Publié par jipicy - Dernière mise à jour le 2 novembre 2009 à 18:03 par marlalapocket




Sujet 9559 - Sed - Introduction à SED - Part II

[ Voir ce sujet en ligne ] - [ Catégorie: Systèmes d'exploitation - Linux - Shell - Sed ]


SED - The Stream EDitor - Part II


Ce document est une introduction à la pratique et à l'utilisation de l'éditeur de flux "SED", qui essaie de couvrir certaines fonctionnalités assez méconnues, pour ne pas dire "quasi inconnues", qui font de "SED" un outil indispensable dans la boîte à outils de tout Linuxien désireux de se rompre aux maniements et aux arcanes du traitement de fichiers via une console et un shell.

Sommaire part II








Partie I
Partie III

Les délimiteurs


Délimiteur de commande


Conventionnellement, Sed utilise comme caractère délimiteur pour son mécanisme de substitution le caractère "/" (slash - barre oblique) :
sed 's/motif/remplacement/' fichier

Dans la plupart des cas, ce choix par défaut est très satisfaisant, mais peut s'avérer vite un vrai casse-tête si le motif ou la chaîne de remplacement contiennent eux aussi un ou des slash(es) comme c'est souvent le cas, par exemple, pour les chemins d'une arborescence (PATH).
Vous pouvez bien évidemment protéger ce(s) slash(es) en les préfixant d'un "\" (backslash - anti-slash - barre oblique inverse), opération très fastidieuse et contraignante s'il en est, si le motif (ou la chaîne de remplacement) en comporte plusieurs et qui plus est, rendant la lisibilité du code assez difficile :
sed 's/\/home\/jp\/Docs\/CCM\/SED/\/mnt\/serveur\/docs/' fichier

voire même impossible lorsque le motif (ou la chaîne de remplacement) est une variable devant être interprétée :
var="/home/jp/Documents/CCM/SED/"
sed 's/'$var'/\/mnt\/serveur\/docs/' fichier

ou (expression entre double quotes)
sed "s/$var/\/mnt\/serveur\/docs/" fichier


Fort heureusement, Sed permet de remplacer le délimiteur par défaut par le caractère de son choix (#,|,!,§,etc.) à partir du moment où il ne se trouve pas dans la composition du motif (ou la chaîne de remplacement) :
sed 's#/home/jp/Docs/CCM/SED#/mnt/serveur/docs#' fichier

Ce caractère peut tout aussi bien être une lettre quelconque si cette lettre ne fait pas partie du motif (ou la chaîne de remplacement) :
echo "bonjour" | sed 'sZbZBZ'


Notez que si vous utilisez le caractère "!" (point d'exclamation) comme séparateur, veillez à entourer l'expression par des quotes simples afin de prévenir toute interprétation par le shell du caractère "!" (employé normalement pour gérer l'historique des commandes).

Délimiteur de motif


Comme nous l'avons vu, Sed utilise des motifs, encadrés par le caractère "/" (slash), pour rechercher (mettre en correspondance) certaines lignes d'un document. Le slash utilisé par convention peut cependant être modifié lui aussi au profit d'un autre caractère tout simplement en faisant précéder la 1ère occurrence de ce caractère par un "\" (backslash).
Prenons toujours l'exemple d'un chemin comme critère de recherche. Sous cette forme, avouez que ce n'est pas trop lisible :

sed -n '/\/home\/jp\/Docs\/CCM\/SED/p' fichier


Alors qu'en choisissant commme caractère délimiteur "#" (dièse) par exemple, ça donnerait :

sed -n '\#/home/jp/Docs/CCM/SED#p' fichier

Le métacaractère &


Bien souvent le mécanisme de substitution se limite à chercher un motif afin de le substituer à lui-même en lui ajoutant une succincte partie comme, par exemple, rechercher la chaîne "Sed the Stream EDitor" dans un document et vouloir lui ajouter systèmatiquement "Sed the Stream EDitor (Éditeur de flux)".
Nous pourrions écrire alors :
sed 's/Sed the Stream EDitor/Sed the Stream EDitor (Éditeur de flux)/g' fichier

Le métacaractère "&" (esperluette) va nous permettre de remplacer toutes chaînes de caractères mises en correspondance par le motif (ou l'expression régulière) fourni en 1er argument.


Ici la notion de 1er argument n'est pas très explicite et peu loquace, mais elle prendra toute son importante avec les expressions régulières et lors du chapitre suivant sur les "sous-expressions".

Donc notre commande s'écrira plutôt de cette façon :
sed 's/Sed the Stream EDitor/& (Éditeur de flux)/g' fichier

Imaginons que nous ayions à rechercher toutes chaînes numériques (1 ou plusieurs chiffres consécutifs) dans un fichier et que nous voulions faire précéder chacune de ces chaînes par "n° " (notez l'espace après le "°"). La commande ressemblerait à :
sed 's/[0-9][0-9]*/n° &/g' fichier


Il faut impérativement utiliser l'expression "\&" pour obtenir un "&" littéral dans une chaîne de remplacement sous peine de générer des erreurs incompréhensibles parfois.

Les sous-expressions et références arrières



Les sous-expressions


\(...\)

Une sous-expression est une partie d'une expression régulière, encadrée par des parenthèses, que l'on souhaite réutiliser dans la chaîne de remplacement. Les parenthèses doivent être elles-mêmes protégées par des backslashes, à moins que l'option "-r" ait été employée.

Les références arrières


\1 \2 \5

Pour faire référence à chaque bloc mis en correspondance dans la chaîne de remplacement, on le désigne par un numéro correpondant à son ordre d'apparition dans l'expression régulière. Ce numéro doit être également protégé par un backslash. On ne peut faire référence qu'à 9 sous-expressions numérotées de \1 à \9. Ces références sont aussi appelées "références arrières".


Voici quelques exemples avec des noms de villes et leur code postal associé :

Fichier de référence :
$ cat plop
31000   Toulouse
34000   Montpellier
66000   Perpignan


Dans cet exemple, la sous-expression "\([0-9]*\)" est mise en correspondance avec toute chaîne exclusivement numérique et est référencée par la référence arrière "\1" :

$ sed 's/\([0-9]*\).*/\1/' plop
31000
34000
66000


Cette fois-ci, nous mettons en correspondance 2 sous-expressions, une exclusivement numérique et l'autre comprenant le reste de la ligne sans toutefois englober le caractère de tabulation qui sépare le code postal du nom de la ville. Nous nous servons ensuite des références arrières "\1" (code postal) et "\2" (nom de ville) pour afficher le résultat sous la forme : nom de ville > code postal

$ sed 's/\([0-9]*\)\t\(.*\)/\2 > \1/' plop
Toulouse > 31000
Montpellier > 34000
Perpignan > 66000


Dans ce 3ème et dernier exemple, nous ferons correspondre une sous-expression à chaque partie de la ligne, à savoir le code postal (\1), la tabulation (\2) et le nom de la ville (\3)

$ sed 's/\([0-9]*\)\(\t\)\(.*\)/\3\2\1/' plop
Toulouse        31000
Montpellier     34000
Perpignan       66000



Une référence arrière peut faire appel à une sous-expression autant de fois que l'on veut dans la chaîne de remplacement. Reprenant le dernier exemple, en voici la démonstration avec la répétition de la tabulation à divers endroits :
$ sed 's/\([0-9]*\)\(\t\)\(.*\)/\2\3\2\2\1/' plop
        Toulouse                31000
        Montpellier             34000
        Perpignan               66000

Expression régulière précédente


Lors de la mise en corrrespondance d'une chaîne avec une expression régulière, Sed met dans sa mémoire tampon ladite chaîne et de ce fait, il est alors possible de se référer à cette chaîne dans la 1ère partie de la commande de substitution "s" (LHS) sans en faire mention littéralement. Autrement dit, une commande du genre 's//chaîne_de_remplacement/' substituera la dernière expression régulière mise en correspondance par Sed par la chaîne_de_remplacement.

Pour illustrer cet état de fait, reprenons notre fichier avec les villes et les codes postaux.
Nous allons chercher la (les) ligne(s) contenant le motif "Montpellier", les autres seront effacées (d) et nous substituerons "Montpellier" par "Béziers" :

$ cat plop
31000   Toulouse
34000   Montpellier
64000   Perpignan

$ sed '/Montpellier/!d; s//Béziers/' plop
34000   Béziers


Pour faire le tour de la question concernant les sous-expressions, références arrières et expression régulière précédente, voilà toujours selon l'exemple précédent une autre facette des possibilités offertes par Sed. Si le motif recherché est encadré par des parenthèses, il devient de ce fait une sous-expression qui peut être appelée dans la partie droite de la commande "s" :

$ sed '/\(Montpellier\)/!d;s//Béziers-\1/' plop
34000   Béziers-Montpellier

$ sed '/\(Mon\)tpellier/!d;s//Béziers-\1blanc/' plop
34000   Béziers-Monblanc

La négation


Il peut s'avérer parfois utile d'exclure une ligne matchant un motif (ou intervalle de ligne) avant d'effectuer un traitement. Pour ce faire, Sed a recours au caractère "!" (point d'exclamation), qui, comme dans la plupart des outils issus du monde Unix, évoque la "négation", exactement comme le fait la commande "grep -v".

Il suffit pour cela de faire suivre le motif (ou le numéro de ligne ou encore l'intervalle de ligne) du caractère "!" comme suit :
sed -n '3 !p' fich.txt
sed -n '3,8 !p' fich.txt
sed -n '/indice/! p' fich3.txt

On rencontre souvent dans les scripts Sed, l'expression "$!" qui peut se traduire par "tant que la dernière ligne n'est pas atteinte" et qui permet d'effectuer une ou plusieurs commande(s) tant que cette condition est vraie.

Il peut être amusant de faire la comparaison entre les différentes façons d'écrire la syntaxe d'une commande pour un résultat identique.
echo -e 'a\nb\n\nc\nd\ne\n\nf\ng' | sed '/./! d'
echo -e 'a\nb\n\nc\nd\ne\n\nf\ng' | sed '/^$/ d'
echo -e 'a\nb\n\nc\nd\ne\n\nf\ng' | sed -n '/^$/! p'
echo -e 'a\nb\n\nc\nd\ne\n\nf\ng' | sed -n '/./ p'

Le regroupement de commandes


/adresse/{...}
(intervalle d'adresse autorisée)
C'est bien là leur principale fonction, cibler une ligne (ou plusieurs) et appliquer successivement une ou plusieurs commande(s) bien spécifique(s). Notons que le traitement agit sur le contenu de la mémoire tampon et non sur la ligne originale et que de ce fait, les changements apportés peuvent conditionnés les critères de sélection ultérieurs.
sed '
/a/{     # seule la ligne contenant "a"
s/a/c/g  # remplacer tous les "a" par "c"
/c/{     # seule la ligne contenant "c" de la ligne matchée
s/c/A/g  # remplacer tous les "c" par "A"
}
}
' < <(echo -e "aaa\nbbb\nccc\nddd")


AAA
bbb
ccc
ddd

 
$ echo -e "aaa\nbbb\nccc\nddd" | sed '/a/{s/a/c/g;/c/{s/c/A/g}}'

AAA
bbb
ccc
ddd


Dans un regroupement de commandes (dans un script), chaque commande doit débuter sur sa propre ligne, les accolades et l'ensemble des commandes doivent être sur des lignes séparées. L'accolade ouvrante doit se trouver en fin de ligne, alors que l'accolade fermante doit impérativement se trouver seule sur une ligne. Attention, aucun espace ne doit figurer après les accolades.

Le remplacement de variables


Il peut arriver qu'à l'intérieur d'un script Sed on ait besoin de passer une variable comme paramètre, que ce soit comme motif ou encore dans l'une ou l'autre des parties (LHS ou RHS) lors d'une substitution. Comme je vous en ai parlé précédemment, il faudra faire très attention aux caractères présents dans la variable afin d'adapter les quotes à utiliser.

En effet, Sed, par défaut, utilise des quotes simples pour entourer ses expressions, or ce mécanisme en shell bloque justement l'expansion des variables ; de ce fait, l'emploi de quotes simples empêchera tout bonnement l'interprétation de la variable.
var=A; echo 'azerty' | sed 's/a/$var/'
$varzerty

Dans un premier temps, il est tout à fait possible de remplacer ces quotes simples par des quotes doubles, ce qui, dans la plupart des cas, suffira amplement à permettre l'interprétation de la variable comme il se doit.
var=A; echo 'azerty' | sed "s/a/$var/"
Azerty

Mais il peut s'avérer judicieux d'employer plutôt cette syntaxe :
var=A; echo 'azerty' | sed 's/a/'"$var"'/'
Azerty

Dans ce cas-là, il n'est pas très aisé de comprendre pourquoi il est préférable d'utiliser un mélange de quotes simples et doubles. En fait, le mot "mélange" n'est pas le terme approprié, il aurait été plus juste d'employer le mot "exclure", car, en effet, par cette syntaxe, nous excluons la variable de l'expression, ce qui permet son interprétation par le shell, mais protège au sein de l'expression elle-même l'interprétation d'éventuels caractères propres au shell. Pour mieux comprendre cette nuance, prenons l'exemple suivant :
L'affichage par le shell de 6 lettres de l'alphabet, chacune sur une ligne et dont la lettre "A" est répétée deux fois. Après avoir affecté cette lettre (A) à une variable ($var), nous allons demander à Sed de ne pas afficher les lignes contenant cette variable, donc en employant la synatxe évoquant la négation, autrement dit le point d'exclamation (!).
Tout d'abord, écrivons l'expression avec des quotes simples :
var=A; echo -e "A\nB\nC\nA\nD\nE" | sed -n '/$var/!p'
A
B
C
A
D
E

Nous constatons que toutes les lettres sont affichées et c'est normal vu que la variable n'a pas été interprétée par le shell à cause des quotes simples.

Maintenant, entourons l'expression avec des quotes doubles :
var=A; echo -e "A\nB\nC\nA\nD\nE" | sed -n "/$var/!p"
-l: !p": event not found

Le shell nous renvoie un message d'erreur ! Effectivement, le "!" est un caractère réservé du shell qui sert notamment pour l'historique des commandes et qui n'a pu être interprété tel quel.

Dissocions donc la variable de l'expression propre à Sed en refermant l'expression juste avant la variable et en la rouvrant juste après à l'aide des quotes simples (notez que les quotes doubles autour de la variable sont facultatives, mais qu'il est préférable de les laisser, parce que c'est une bonne habitude à prendre et pour se prémunir d'éventuelles erreurs dues à des espaces au sein de la variable) :
$ var=A; echo -e "A\nB\nC\nA\nD\nE" | sed -n '/'"$var"'/!p'
B
C
D
E

Les expressions régulières


La connaissance des expressions régulières (regex en abrégé) est un petit plus non négligeable dans la pratique de Sed (et de bien d'autres langages).

Une expression régulière est un motif (pattern en anglais) qui entre en correspondance, de la gauche vers la droite, avec une chaîne de caractères.

Les expressions régulières tirent leur puissance de leurs capacités d'inclure des alternatives et des répétitions dans l'élaboration du modèle constituant le motif. Ces spécificités sont élaborées à l'aide de caractères spéciaux, qui ne sont pas interprétés au sens littéral du terme, mais d'une façon spécifique.

Voici une brève description de la syntaxe des expressions régulières utilisée dans Sed.

caractère (un caractère quelqconque)

\+

\?

\{i\}

\{i,j\}

\{i,\}

\(regexp\)

. un point

^

$

[liste]
Les caractères $, *, ., [, et \ ne sont pas normalement considérés comme des caractères spéciaux à l'intérieur d'une liste. Ainsi l'expression [\*] correspondra autant au caractère \ qu'au caractère *, le \ n'étant pas vu comme un caractère d'échappement servant à protéger le caractère *.

[^liste]

regexp1\|regexp2

\nombre

\n

\métacaractère

Note :

Les caractères d'échappement


\a
\b
\f
\n
\r
\t
\v
\o000
\dDDD
\xHH

Les extras


\`
'
\b
\B
\w
\W
\s
\S
\<
\>
\e
\l
\L
\u
\U

Les classes de caractères


[:alnum:]
[:alpha:]
[:digit:]
[:lower:]
[:upper:]
[:print:]
[:punct:]
[:space:]
[:blank:]
[:graph:]
[:cntrl:]
[:xdigit:]

Les différentes versions


Unix


Windows


Debuggers


Voilà 2 debuggers qui vous permettront de mieux comprendre le fonctionnement de Sed et, dans quelques cas particuliers, vous économiseront de nombreuses heures à vous arracher les cheveux en essayant de trouver où se situait le grain de sable qui obstruait votre joli filtre devenu tout à coup imperméable...

Voilà un mini tutoriel pour l'emploi de "sedsed".
Usage : sedsed OPTION [-e sedscript] [-f sedscriptfile] [inputfile]

OPTIONS :

     -f, --file          lecture des commandes depuis le fichier désigné
     -e, --expression     permet d'enchaîner plusieurs commandes à la suite
     -n, --quiet          demande implicite de ne pas afficher l'état de la mémoire principale
         --silent         alias pour --quiet

     -d, --debug          active le mode debugage
         --hide           cache certaines options de débogage (options : PATT,HOLD,COMM)
         --color          active la sortie du débogage colorée (activée par défaut)
         --nocolor        désactive la sortie du débogage colorée
         --dump-debug     listage du débogage à l'écran

     -i, --indent         indentation du script, une commande par ligne
         --prefix         indentation préfixée par des espaces ou des tabulations (4 espaces par défaut)

     -t, --tokenize       mode verbeux, affiche chaque commande avec plus d'informations
     -H, --htmlize       convertit un script sed en une jolie page HTML colorée

     -V, --version        affiche la version du programme et quitte
     -h, --help           affiche une page d'aide et quitte


Signification en sortie :
PATT : Affiche le contenu de l'espace de travail (mémoire principale)
HOLD : Affiche le contenu de l'espace annexe (mémoire secondaire)
COMM : La commande SED devant être exécutée
$ Délimite le contenu de PATT et HOLD



La syntaxe la plus courante reste le mode débogage simple (-d) :
echo -e "AAA\nBBB\nCCC\nDDD" | sed '/BBB/ {n;s/C/Z/2}'
echo -e "AAA\nBBB\nCCC\nDDD" | sedsed -d '/BBB/ {n;s/C/Z/2}'

<a href='../images/0-B4IoZAnt-debogage-d.png'><a href='../images/0-B4IoZAnt-debogage-d.png'><a href='../images/0-B4IoZAnt-debogage-d.png'>
</a></a></a>
Schéma : debogage_-d.png

En mode indentation :
sedsed -i -n ':notag;/tag/!{1!H;1h;x;s/\n/ /g;x;$b lastline;d;};/tag/{x;/^$/!p;$b lastline;d;b notag;};:lastline;x;p;'


Schéma : debogage_indent.png

Cacher l'affichage de l'espace annexe :
echo -e "AAA\nBBB\nCCC\nDDD" | sedsed -d --hide=HOLD -n '/BBB/ {n;s/C/Z/2p}'

Quand ne dois-je pas utiliser Sed ?


Quand des outils spécifiques existent déjà et effectuent la tâche plus rapidement et plus simplement, (syntaxiquement parlant).

Pour certaines tâches dont "awk" et "perl" s'acquittent de façon plus simple et plus rapide, comme par exemple :

Limites connues des différentes versions


Voici quelques limites connues sur les versions distribuées de Sed, dépendantes bien entendu de son matériel, de sa mémoire, de son système d'exploitation et des bibliothèques C utilisées lors de la compilation de Sed.

Les références


Vous trouverez ci-dessous les ouvrages ainsi que les sites qui m'ont servi à élaborer ce document.

Livres


Les liens


Débutants et initiés


Gurus


IRC


SED - The Stream EDitor - Part III


Suite et fin => SED - The Stream EDitor - Part III
Publié par jipicy - Dernière mise à jour le 13 novembre 2009 à 13:46 par marlalapocket





© Tous droits réservés 2010 Jean-François Pillou