Photographie
[PERL] une autre utilisation de l’opérateur “..”
Tout développeur ou ingénieur système qui a mis son nez dans du code perl connait surement déjà l’opérateur “..” ou range qui est le plus souvent utilisé pour construire une énumération.
Par exemple: my @array = (1..10); remplit @array d’un tableau comprenant tous les éléments de 1 à 10.
[vincent@Amyrlin ~ 10:46:55] perl -e 'print join(" ",(1..10)),"\n"'
1 2 3 4 5 6 7 8 9 10
Un collègue m’a faire découvrir hier une utilisation que le pense assez méconnue de cet opérateur, et que j’ai trouvée fantastique à la lecture de son code.
Effectivement, je n’avais jusqu’à présent rencontré que dans un contexte de liste, mais son utilisation en contexte scalaire est toute autre.
In scalar context, ".." returns a boolean value. The operator is bistable,
like a flip-flop, and emulates the line-range (comma) operator of sed, awk,
and var-ious editors. Each ".." operator maintains its own boolean state.
It is false as long as its left operand is false. Once the left operand is
true, the range operator stays true until the right operand is true, AFTER
which the range operator becomes false again. It doesn't become false till
the next time the range operator is evaluated. It can test the right operand
and become false on the same evaluation it became true (as in awk), but it
still returns true once. If you don't want it to test the right operand
till the next evaluation, as in sed, just use three dots ("...") instead
of two. In all other regards, "..." behaves just like ".." does.
En clair cet opérateur a un état qui parmet de comparer deux conditions dans le temps. En particulier son utilisation dans un test conditionnel a l’intérieur d’une boucle sur une liste permet de sélectionner une sous partie de cette liste. En fait comme en awk cela permet par exemple d’appliquer un bloc de code à une sous liste déterminée par 2 conditions, une condition de début et une de fin.
En pratique nous l’avons utilisée pour appliquer un bout de code à un bloc de texte dans un fichier de config. Voici un exemple concret d’utilisation. Nous avons un fichier de config sur chaque serveur qui doit contenir une partie commune à tous les serveurs délimitée par des bannières prédéfinies et une partie spécifique à chaque machine. Nous avons pu utiliser le code suivant pour scripter une modification de la partie commune:
Voici le fichier de config:
[vincent@Amyrlin ~ 11:05:20] cat toto.conf # BEGIN UNIX TEAM This is a common configuration par V1. config1=a config2=b # END UNIX TEAM This is a specific part
Et voici le code:
[vincent@Amyrlin ~ 11:05:40] cat toto.pl
#!/usr/bin/perl -w
my $newconfig="# BEGIN UNIX TEAM
This is a common configuration par V2.
config1=a
config2=b
config3=c
# END UNIX TEAM
";
my $conf=$newconfig;
while (<>) {
$conf .= $_ unless (/^# BEGIN UNIX TEAM/ .. /^# END UNIX TEAM/)
}
print $conf;
Exemple d’utilisation:
[vincent@Amyrlin ~ 11:06:10] ./toto.pl toto.conf # BEGIN UNIX TEAM This is a common configuration par V2. config1=a config2=b config3=c # END UNIX TEAM This is a specific part
C’est bien sur une utilisation simple mais on peut imaginer des chose beaucoup plus puissantes que cette simple substitution de bloc…
A vous de jouer. Et je remercie donc Pierre MACHARD pour m’avoir fait découvrir cette petite PERLe.
| Print article | This entry was posted by Vincent on 11 October 2008 at 11:08, and is filed under PERL. Follow any responses to this post through RSS 2.0. You can leave a response or trackback from your own site. |
![[lang_fr]trackpad[/lang_fr] configuration du trackpad sous Tiger](http://vin0x64.fr/wp-content/uploads/2009/03/trackpad.jpg)
English
about 1 year ago
Effectivement, c’est très joli! Par contre, si je lis bien, quelle que soit la position de ton bloc de texte dans le fichier d’origine, il va se retrouver au début après modification.
Evidemment, ça se règle facilement, mais le code sera moins élégant
about 1 year ago
Certes, mais dans mon cas précis c’est bien ce qu’on attend… donc c’est bon.
about 1 year ago
Je viens de découvrir la version ruby du meme style d’opérateur, c’est encore plus pervers. Je ne resiste pas a l’envie de le partager:
file = File.open(“ordinal”)
while file.gets
print if ($. == 1) || /eig/ .. ($. == 3) || /nin/
end
produces:
first
second
third
eighth
ninth
Extrait de http://www.ruby-doc.org/docs/ProgrammingRuby/