[zsh] Petit exemple de parsing d'un fichier texte simple

Bruno Bonfils asyd at asyd.net
Thu Sep 7 17:24:48 CEST 2006


Bonjour à tous,

comme vous le savez sans doute, zsh offre de nombreuses fonctions de
pattern matching qui permettent - dans des cas relativement simples - de
se passer des outils tel que awk, sed, etc..

Je vous propose donc de découvrir ces fonctionnalitées via un petit
exemple pratique.

Soit le fichier suivant :

,------ /etc/zones/index
| # Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
| # Use is subject to license terms.
| #
| # ident "@(#)zones-index        1.2     04/04/01 SMI"
| #
| # DO NOT EDIT: this file is automatically generated by zoneadm(1M)
| # and zonecfg(1M).  Any manual changes will be lost.
| #
| global:installed:/
| tools:installed:/zones/tools:00000000-0100-0000-2879-0408fb610508
| databases:installed:/zones/databases:00000000-0100-0000-2879-0408fb610508
| public-ejbca:installed:/zones/public-ejbca:00000000-0100-0000-e078-0408fb610508
| public:installed:/zones/public:00000000-0100-0000-c078-0408fb610508
`---

Mon objectif est d'obtenir la liste des premiers mots des lignes non
commentées (c'est à dire global, tools, databases, etc...). Pour y
parvenir, j'ai choisi de créer un tableau de lignes, supprimer les
lignes qui contiennent # au début, puis supprimer des lignes ce qui suit
le premier :

comme on l'a vu ce matin, l'utilisation de ("${(f)$(< fichier)}")
permet de créer un tableau de lignes à partir du fichier donné. En fait,
je rajoute simplement deux substitutions au résultat obtenu.

La première est ##\#* qui permet de supprimer tout ce qui suit #* (la
variable obtenu par ("${(f)$(< fichier)}") étant déjà un tableau, ca
supprime les lignes commentés), notez que # à une signification (1), il
faut donc escaper mon caractère #, et comme je veux supprimer toute la
ligne, je rajoute *, ce qui donne donc ${name##\#*}

La seconde est //:* (2)  (sous entendu /:*/) qui permet de supprimer tout
ce qui suit :* 

Ce qui pourrait donc nous donner quelque chose du genre :

,------
| % lines=("${(f)$(< /etc/zones/index)}")
| % nocomments=(${lines##\#*})
| % zones=(${nocomments/:*/})
| % echo $zones
| global tools databases public-ejbca public
`---

Ce qui nous donne en oneliner :

,------
| % zones=(${${(a)"${(f)$(< /etc/zones/index)}"##\#*}/:*})
| % print -a $zones
| global tools databases public-ejbca public
`---

Et voilà ! pas de fork, rien que du pur zsh, et du français loin d'être
pur, lui :) J'espère que cela vous sera utile.

Notes (section 13, mais vous commencez à en avoir l'habitude :)

1) ${name#pattern}, ${name##pattern}

If the pattern matches the beginning of the value of name, then
substitute the value of name with the matched portion deleted;
otherwise, just substitute the value of name. In the first form, the
smallest matching pattern is preferred; in the second form, the largest
matching pattern is preferred.

2) ${name/pattern/repl}, ${name//pattern/repl}

Replace the longest possible match of pattern in the expansion of
parameter name by string repl. The first form replaces just the first
occurrence, the second form all occurrences. 

-- 
http://asyd.net/home/   - Home Page
http://guses.org/home/  - French Speaking Solaris User Group


More information about the Shell mailing list