3. Eléments d'initiation à  sed

3.1. Principes généraux

Sed et Awk sont deux outils de textprocessing, invoqués de la même manière :

command [options] script filename

Comme la plupart des programmes UNIX, sed et awk peuvent lire sur l'entrée standard et écrire sur la sortie standard, mais aussi recevoir un flux de données depuis un fichier, et bien sûr rediriger les sorties vers un fichier.

Le script spécifie les intructions à  exécuter, et doit être quoté (encadré d'apostrophes) si il est directement codé sur la ligne de commande. Une option est commune à  awk et sed, -f , qui permet de spécifier un script externe.

sed -f scriptfile inputfile

La figure ci-dessous montre le fonctionnement de base de sed et awk. Chaque programme lit ligne par ligne le fichier d'entrée, en fait une copie, et exécute les instructions prévues dans le script sur cette copie. Les changement n'affectent pas le fichier source.

Figure 1. Fonctionnement de Sed et Awk

Fonctionnement de Sed et Awk

3.2. Commandes Sed

  1. Commande de substitution

    • La commande s permet d'effectuer des substitutions suivant la syntaxe : sed -e 's/expr-régulière/remplacement/options'

    • Options

      • Sans précision, la commande ne s'applique qu'à  la 1ère occurence de chaque ligne

      • 0...9 : indique que la substitution ne s'applique qu'à  la nième occurence

      • g : effectue les modifications sur toutes les occurences trouvées

    • Exemple : sed -e 's/moi/toi/g' fich.moi > fich.toi le fichier fich.moi est parcouru, à  chaque occurrence de "moi", ce mot est remplcé par "toi" et le nouveau fichier est sauvegardé sous le nom fich.toi

  2. Destruction ou sélection

    • Cette option permet de filtrer les lignes qui satisfont une expression régulière. Ces lignes ne sont pas détruites dans le fichier d'origine, mais ne sont pas transmise en sortie.

    • Par exemple, pour détruire toutes les lignes vide d'un fichier : sed -e '/^$/d'

  3. Ajout, insertion et modification

    • Pour utiliser ces commandes, il est nécessaire de les saisir sur plusieurs lignes

      sed [adresse] commande\ expression

    • La commande peut être :

      • a pour ajout ;

      • i pour insertion ;

      • c pour modification

    • Exemple :

      /<Neotech 3>/i\ CPEN GREATTA - NEOTECH 3\ Cité scolaire du butor

3.3. Quelques exemples

Exemple : supprimer les lignes commençant par un commentaire dans le fichier suivant : /etc/hosts

EXEMPLE :

$ sed -e '/^#/d' /etc/hosts > ~/myhosts                                         

Le fichier résultant est nommé ~/myhosts. L'expression utilisée est vraie pour toute chaîne commençant par le caractère # (marque de commentaire dans un fichier).

Remplacer toutes les occurences de l'interface rl0 du fichier (FreeBSD) /etc/ipf.conf, par l'interface xl1 :

EXEMPLE :

# sed -e 's/rl0/xl1/g' /etc/ipf.conf > /etc/ipf.conf.new                        

Le # dénote ici une opération effectuée en tant que super-utilisateur root. L'expression commence par un s, lequel indique une opération de substitution. Le g, quant à  lui indique que tous les remplacements sur une ligne doivent être fait, en son abscence seule la première occurence trouvée sur la ligne serait remplacée.

Quelques expressions régulières. Ces exemples montrent l'utilisation d'expressions régulières, nous rappelons dans ce qui suit quelques méta-caractères importants :

Tableau 1. Expressions régulières

CaractèreDescriptionExemple
^Correspondance avec le début de ligne/^#/ ligne commençant par un un #.
$Correspondance avec la fin de ligne/^$/ ligne blanche.
.Correspondance avec un caractère quelconque/../ ligne contenant au moins deux caractères quelconques.
*Correspondance avec 0 ou plusieurs caractères quelconques./^a*/ ligne commençant par a suivit par n'importe quoi.
[]Correspondance avec tout caractères de l'intervalle/[abc]$/ ligne se terminant par le motif abc.


Donnons un autre exemple de combinaison d'expressions régulières. On cherche à  imprimer (si elle existe) la fonction main d'un script Perl :

EXEMPLE :

$ cd bin ; sed -n -e '/sub[[:space:]]*main[[:space:]]*{/, /^}/p' *.pl | less    

La première partie de cette expression régulière sub[[:space:]]*main[[:space:]]*{ permet de trouver le début de la définition de la fonction main, tandis que la seconde /^}/ trouve la fin du bloc de cette fonction. La classe spéciale [[:space:]] permet de dénoter un caractère espace ou un caractère TAB. Enfin, la commande p imprime les lignes qui vérifient la condition.

Quelques classes. 

Tableau 2. Expressions régulières

ClasseSémantique
[:alnum:]Caractères alphanumérique : [a-zA-Z0-9].
[:alpha:]Caractères alphabétiques : [a-zA-Z].
[:blank:]Caractère espace ou tabulation.
[:digit:]Chiffre [0-9].
[:lower:]Caractères minuscules [a-z].
[:space:]Espace.
[:upper:]Caractères majuscules [A-Z].
[:cntl:]Caractère de contrôle.
[:graph:]Caractère visibles (donc sans l'espace).
[:print:]Caractère autres que les caractères de contrôle.
[:punct:]caractères de ponctuation.
[:xdigit:]Chiffres héxadécimaux [0-9a-fA-F].


Donnons maintenant un autre exemple faisant intervenir la mémorisation d'expression. On veut cette fois ci remplacer les occurences d'adresses IP du fichier /etc/hosts, par leur adresse dans le domaine in-addr.arpa :

EXEMPLE :

$ awk -F" " '{print $1}' /etc/hosts | sed -e 's/\([[:digit:]]*\)\.\([[:digit:]]*
\)\.\([[:digit:]]*\)\.\([[:digit:]]*\)/arpa.in-addr.\3.\2.\1/' -e '/^#/d'

arpa.in-addr.200.168.192
arpa.in-addr.200.168.192

arpa.in-addr.1.168.192
arpa.in-addr.1.168.192

On utilise maintenant les parenthèses de mémorisation, autour de classes. L'opérateur * permet d'attendre plusieurs chiffres. On reconnaît l'expression qui permet de filtrer les adresses IPv4. L'expression \3 dénote la troisième expression mémorisée i.e. le troisième octet, tandis que \2 désigne la deuxième expression...

On peut combiner les instructions, il suffit pour cela de rajouter autant d'option -e que nécessaire. Si cela devient trop complexe, on peut tout placer dans un fichier et l'appeler au besoin avec l'option -f.

Il est possible d'effectuer plusieurs transformations sur la même région (zone dénotée par un début et une fin : étiquettes ou numéro de lignes). Dans l'exemple qui suit nous proposons de transformer certains termes dans une région dont le début est marquée par une ligne commençant par le mot BEGIN et se terminant par le mot END (ou la fin de fichier si ce mot n'est pas trouvé).

EXEMPLE :

#
# ~/mycommand.sed                                                               
#

/^BEGIN/, /^END/ {
    s/[Ll]inux/GNU\/Linux/g
    s/[Oo]penbsd/OpenBSD/g
    s/[Ff]reebsd/FreeBSD/g
    s/[Nn]etBSD/NetBSD/g
}


USAGE :

$ sed -n -f ~/mycommand.sed myfile.txt > res.txt

3.4. Exercices

Exercice 1

Créez un nouveau répertoire ~/elementBase/part3/. Copiez y le fichier ps-aux que nous avions utilisé lors de la dernière séance.

Travail à  faire. 

  1. Supprimer les processus dont le propriétaire est root, et placez le résultat dans my_ps-aux

  2. Modifiez le nom du propriétaire sysop, en le remplaçant par le votre. Le résultat est placé dans my_ps-aux

  3. Supprimez les éventuels chemins des exécutables. (/bin/tcsh deviendra tcsh)

Exercice 2

On dispose d'un répertoire web contenant des fichiers html, pour lesquels on voudrait changer toutes les occurences des images au format gif par des images identiques au format png.

Travail à  faire. Proposer un script qui effectue ces changements dans tous les fichiers. On sauvegardera de plus tous les anciens fichiers dans un sous-repértoire nommé BAK.

Proposition de correction. On se place dans le repertoire cible.

SCRIPT SHELL (sh) :

if [ ! -d BAK ]; then mkdir BAK; fi && \                                        
for f in `find . -name "*.htm[l]" -print`; do
  cp $f BAK
  sed -e 's/.gif/.png/g' < $f > $f.tmp
  mv $f.tmp $f
done

Skins :
Transparence
Simple
Page Accueil
Formation