jeudi, avril 27 2006

Script sed pour joindre deux lignes

Suite à mon précédent billet et avec l'aide de Christophe, j'ai fini par trouver comment joindre deux lignes d'un fichier si la première ligne correspond à un modèle. Pour cela, j'utilise sed de cette façon :

sed -e '/<screen>$/N; s/<screen>
/<screen>/;' fichier_avant > fichier_apres

sed lit un fichier ou l'entrée standard ligne par ligne. Cet outil place tout d'abord la ligne lue dans un tampon et va exécuter les instructions spécifiées sur ce tampon.

La première instruction, /<screen>$/N, va chercher une ligne finissant (car $) par <screen>. Le N lui demande d'ajouter un retour chariot dans le tampon ainsi que la prochaine ligne en attente. Je vais donc me trouver avec un tampon contenant la jointure des deux lignes dont la première finit par <screen>.

La deuxième instruction s'exécute à partir du tampon et est plus habituelle : s/<screen> /<screen>/. Cette instruction va donc supprimer tout simplement le retour chariot compris dans le tampon.

Cela fonctionne parfaitement. J'ai donc mis tout ça dans le petit script que voici :

for fichier in *.sgml
do
  backup=${fichier}.bak
  mv ${fichier} ${backup} && \
    sed \
      -e '/<screen>$/N; s/<screen>
/<screen>/;' \
      -e '/<synopsis>$/N; s/<synopsis>
/<synopsis>/;' \
      -e '/<literallayout>$/N; s/<literallayout>
/<literallayout>/;' \
      -e '/<programlisting>$/N; s/<programlisting>
/<programlisting>/;' \
      ${backup} > ${fichier}
done

Une fois exécuté, j'ai pu faire mon commit et améliorer encore le PDF :)

dimanche, juillet 24 2005

Dans la collection « Je fais mumuse avec sed »

À chaque nouvelle mise à jour de la traduction de LFS, je m'amuse à modifier tous les fichiers du site web. En effet, ce site est totalement statique. Je ne reviendrais pas sur les avantages d'un site statique car, en l'occurence, c'est son défaut qui m'intéresse aujourd'hui. Comme ce site est totalement statique, le menu à droite est présent sur toutes les pages. Cela veut dire que si je veux ajouter un élément dans le menu, je suis obligé de modifier toutes les pages... ce n'est vraiment pas un petit inconvénient vu que je compte 488 pages sur ce site (principalement à cause des pages de réservation pour chaque chapitre des livres LFS et BLFS). Auparavant, je me contentais de modifier les pages principales (une dizaine) mais çe ne me rendait pas très fier du travail réalisé. De plus, je faisais ça souvent rapidement : je corrigeais un menu d'un fichier puis je partais dans un copier/coller de folie sur les autres pages. Malheureusement, le menu indique sur quelle page vous vous trouvez en surlignant la ligne représentant la page... avec le copier/coller, tout le monde pensait rester sur la même page. Je devais donc quand même modifier chaque page manuellement.

M'étant amusé avec sed il y a peu de temps, je me suis dit qu'il serait bien que je me casse la tête une bonne fois pour toutes, histoire de règler définitivement ce problème. La règle est simple : remplacer tous les « LFS-6.0 » par des « LFS-6.1 ». La commande sed suivante le fait (sur un seul fichier, mais on verra ce problème plus tard) :

sed -e 's/LFS-6.0/LFS-6.1/g' downloadmanual.html

Pas mal... mais je me rend compte que, si le texte affiché est bien en majuscule, les liens, eux, sont en minuscules. Très bien, corrigeons cela...

sed -e 's/LFS-6.0/LFS-6.1/gi' downloadmanual.html

Trop facile... ah oui, mais, du coup, mes liens se retrouvent en majuscules... grmblll... bon, nouvelle tentative :

sed -e 's/\(LFS\)-6.0/\1-6.1/gi' downloadmanual.html

Les parenthèses me permettent de conserver l'état dans une première sauvegarde, le \1 permet de la restituer. Très bien. Ah, ce n'est pas fini, il semble que mes liens BLFS-6.0 se soient aussi transformés en liens BLFS-6.1... déjà que la mise à jour de BLFS-6.0 n'est pas terminée, je ne vais pas non plus passer tout de suite à la version suivante :) nouvelle rectification

sed -e 's/\([^B]\)\(LFS\)-6.0/\1\2-6.1/gi' downloadmanual.html

Oula, c'est tout de suite plus compliqué. [^B] veut dire tout sauf le caractère B. Je le sauvegarde pour pouvoir le restaurer après, histoire qu'il ne soit pas supprimé dans la bataille.

Il ne reste plus qu'à écrire le petit script qui se charger de modifier tous les fichiers :

find . -name "*.html" | while read fichier
do
  mv ${fichier} ${fichier}.bak
  cat ${fichier}.bak | sed -e "s/\([^B]\)\(LFS\)-6.0/\1\2-6.1/gi" > ${fichier}
done

Voilà, c'était facile, pas cher et ça fait gagner beaucoup de temps.