On Mon, 21 Oct 2002 14:44:07 +0200
Bernard Lambey <[EMAIL PROTECTED]> wrote:
~~~~~~~~~~~~~~~~~~~~
> Jipe! quand je parlais d'exemples l'autre jour... Dis? Ne pourrais-tu
> nous rendre le service de commenter longuement, largement et...
> en travers ce programme bash. Je crois que tu ferais grand plaisir
> � ceux qui, comme moi, essaient de comprendre qqchose au bash...
> Merci
> Bernard L.
> --
pourquoi pas ?
par contre, permets moi de changer le titre du fil... bash contre perl ? surtout pas.
non seulement pour ne pas r�veiller tous les trolls de la montagne, mais aussi parce
que �a n'a pas lieu d'�tre... ni contre python ou ruby. et puis le script en question
est un peu une r�invention du fil � couper le beurre. juste un d�fi amusant � relever.
donc voici la b�te:
#!/bin/bash
IFS=$(echo -e "\r")
i=$(cat $1)
a=0
while [ $a -lt ${#i} ]
do
b=${i:$a:1}
case ${i:$a:8} in
\<[aA]\ [hH][rR][eE][fF]=)
echo -n "${i:$a:8}"
a=$((a+8))
while true
do
b=${i:$a:1}
case $b in
\>)
echo -n "$b"
a=$((a+1))
break
;;
[A-Z])
echo -n "$b" | tr
[:upper:] [:lower:]
a=$((a+1))
;;
*)
echo -n "$b"
a=$((a+1))
;;
esac
done
;;
*)
echo -n "$b"
a=$((a+1))
;;
esac
done
echo
qu'est-il sens� faire ?
rechercher dans un fichier html les balises <a href=" "> quelle que soit la casse de
a href et changer les majuscules en minuscules apr�s le = � l'int�rieur de ces balises.
tout d'abord la base du script.
il s'agit du script suivant que je vais d'abord analyser:
#!/bin/bash
IFS=$(echo -e "\r")
i=$(cat $1)
a=0
while [ $a -lt ${#i} ]
do
b=${i:$a:1}
echo -n "$b"
a=$((a+1))
done
echo
la 1�re ligne "#!/bin/bash" est appel�e shebang pour shell et bang qui d�signe le "!".
elle permet, lorsque le script est invoqu� par son nom, d'appeler l'interpr�teur qui
va bien. dans ce cas, le script doit �tre ex�cutable. on peut s'en passer et appeler
le script en argument de l'interpr�teur: "/bin/bash script". dans ce cas, le script
n'a pas besoin d'�tre ex�cutable.
la variable $IFS est par convention le s�parateur de champ interne. elle permet de
d�finir le ou les s�parateur de champ pour la suite du script.
dans le cas pr�sent, le s�parateur de champ sera le retour charriot. ce qui permet
d'inclure dans la variable $i, � la ligne suivante, le tabulations et sauts de ligne
rencontr�es par la commande cat $1. elles �quivaudront � un caract�re.
la 3�me ligne d�finit la variable $i. celle ci contient donc le r�sultat de la
commande "cat $1". $1 est le 1er argument fourni � l'�vocation du script. tout fichier
text devrait faire l'affaire.
la 4�me ligne d�finit � 0 la variable $a qui a son utilit� dans la boucle while qui
suit.
la boucle while donc. de la forme while condition; do commande; done. ou, pour les non
anglophones, tant que condition; faire commande; fait.
la condition:[ $a -lt ${#i} ]
${#i} correspond � la longueur de la chaine de caract�res contenue dans $i. la boucle
ne s'arr�tera que lorsque $a sera �gale � ${#i}.
1�re commande: b=${i:$a:1}
petite digression... d�finissons $toto
$ toto=abcdefghijklmnopqrstuvwxyz
quelle est la longueur de $toto ?
$ echo ${#toto}
26
d�coupons $toto � partir du 20�me caract�re exclus, jusqu'� la fin
$ echo ${toto:20}
uvwxyz
d�coupons 7 caract�res � partir du 3�me inclus
$ echo ${toto:2:7}
cdefghi
donc b=${i:$a:1} va d�finir $b comme contenant une chaine de caract�res partant de $a,
au d�part 0, donc le 1er caract�re de $i et de 1 caract�re. $a �tant indent� par la
suite.
2�me commande: echo -n "$b"
$b est affich� dans le terminal, ou dans un fichier si la sortie du script est
redirig�e vers un fichier avec > fichier.
-n supprime le saut de ligne que rajoute normalement echo.
3�me commande: a=$((a+1))
autre digression... bash permet des op�rations alg�briques simples avec des nombres
entiers.
$ echo $((2+3))
5
$ echo $((2*3))
6
$ echo $((2/3))
0 <- attention! le r�sultat est un entier. donc valeur enti�re par d�faut.
$ echo $((2-3))
-1 <- et l�, un entier n�gatif.
$ echo $((2**3))
8
etc...
on peut utiliser des "()" comme dans toute expression alg�brique
$ echo $((3-(2-1)))
2
$ echo $(((3-1)*6+(2+2)**2))
28
donc $a, qui valait 0 au d�part, vaudra a+1 pour la boucle suivante. ce qui signifie
qu'a chaque boucle, $b va se d�placer dans la chaine $i de 1 caract�re, exactement
comme un curseur...
l'avant derni�re ligne "done", signifie la fin de la boucle, et la derni�re "echo",
permet seulement le retour � un prompt situ� en d�but de ligne � la fin du script et
non en bout de la ligne pr�c�dente.
maintenant que peut-on en faire ?
dans le script de d�part, je cherche � trouver une chaine "<a href=" quelle que soit
la casse. je la fais chercher par un "case".
case ${i:$a:8} in
\<[aA]\ [hH][rR][eE][fF]=)
le curseur $b se d�place dans $i en fonction de la valeur de $a. je rappelle que
b=${i:$a:1}. si les 8 caract�res � partir de $b, cad ${i:$a:8} (tout le monde suit?)
correspondent � cette recherche, mat�rialis�e par la ligne se terminant par ")", o� le
"\" prot�ge le "<" et l'espace d'une interpr�tation erron�e, et [aA] signifie a ou A
et ainsi de suite..., les actions suivantes vont �tre entreprises.
echo -n "${i:$a:8}"
a=$((a+8))
les 8 caract�res � partir de $b vont �tre envoy�e vers la sortie, �cran ou fichier et
$a est augment�e de +8. le curseur $b se d�place donc de 8 caract�res vers la droite.
ensuite vient une autre boucle while toujours vraie "true", qui va d�placer le curseur
$b jusqu'a la fin de la balise ">" et changer les majuscules en minuscules au passage.
while true
do
b=${i:$a:1}
# le curseur se d�place de 1 caract�re vers la droite
case $b in
\>)
echo -n "$b"
a=$((a+1))
break
;;
# si le signe ">" est rencontr�, la boucle while est rompue avec break
[A-Z])
echo -n "$b" | tr [:upper:] [:lower:]
a=$((a+1))
;;
# si un caract�re majuscule est rencontr�, il est tranform� en minuscule grace � tr
*)
echo -n "$b"
a=$((a+1))
;;
# dans les autres cas, rien de sp�cial ne se passe
esac
done
� chaque fois, bien sur, $a est augment� de 1 pour d�placer le curseur et le r�sultat
envoy� vers la sortie, �cran ou fichier.
dans le 1er cas, donc, des actions ont �t� d�finies si les 8 caract�res qui suivent le
curseur correspondent au motif de la recherche. actions contenues dans une boucle
while et un case. il faut bien ensuite d�finir ce qui se passe, s'ils ne correspondent
pas! c'est le 2�me cas...
*)
echo -n "$b"
a=$((a+1))
;;
le * signifie "n'importe quoi" ou plut�t "dans tous les autres cas". c'est forc�ment
le dernier motif de recherche, lorsque tous les cas particuliers ont �t� recherch�s.
donc dans tous les autres cas, on envoye $b vers la sortie, et on augmente $a de 1
pour d�placer le curseur.
voil�! on peut faire plein d'autres choses. du plus simple, comme compter le nombre de
fois o� apparaissent les noms des doctes Nanard, Ismael ou Didier dans un fichier, ou
de plus compliqu�es comme leur adjoindre une balise <I> </I> ainsi qu'un nombre de 1 �
3 en fonction du 1er rencontr�, puis du 2�me, puis du 3�me et qui leur soit propre
tout au long du fichier et permette de renvoyer � un commentaire en fin de page
concernant leur vie, leur oeuvre et leurs travers secrets...
en esp�rant avoir r�pondu � votre demande!
bye
jipe
Vous souhaitez acquerir votre Pack ou des Services MandrakeSoft?
Rendez-vous sur "http://www.mandrakestore.com"