Article publié dans Linux Magazine 63, juillet/août 2004.
Les distributions GNU/Linux récentes comportent un outil peu connu,
seq(1)
, qui permet de générer une liste de nombres successifs.
Néanmoins, étant une innovation GNU, il n'est pas disponible sur les
autres systèmes Unix (et non-Unix). On peut remédier à ceci en écrivant
un outil similaire en Perl.
Une première version très simple peut s'écrire avec cet uniligne qui affiche les nombres de 1 à 10 :
$ perl -le print,for+shift..shift 1 10
C'est suffisant s'il s'agit juste de générer une liste de nombres, mais si le but est de s'en servir dans un format (pour générer une liste de noms successifs par exemple), on peut gérer cela directement dans Perl. Ainsi cet uniligne affiche les valeurs hexadécimales des nombres de 27 à 33 :
$ perl -e 'printf$ARGV[0].$/,$_ for+shift..shift' 27 33 "%02X"
Cette seconde version impose de spécifier le format. Si on veut conserver la possibilité de générer une bête liste de nombres (comme dans le premier exemple), il suffit de rajouter un format par défaut :
$ perl -e '$ARGV[2]||="%s";printf$ARGV[0].$/,$_ for+shift..shift' DEBUT FIN FORMAT
Si on sauve cette commande dans un script seq.pl
, L'exécution de
$ seq.pl 1 7 'fichier.%03d'
affiche la liste des noms de "fichier.001"
à "fichier.007"
.
L'aspect intéressant est qu'on profite « gratuitement » de l'incrémentation
magique de Perl, qui sait traiter les lettres en plus des nombres. Ainsi,
$ seq.pl xaa xah
donne les noms des quelques premiers fichiers créés par split(1)
.
Quelque chose que le seq(1)
de GNU ne sait pas faire.
(Sébastien Aperghis-Tramoni (Maddingue), Marseille.pm - sebastien@aperghis.net
)
glob
La fonction glob()
sert en général à obtenir une liste de fichiers
à partir d'un motif comme ceux utilisés par le shell csh :
$ ls perles*.pod perles-01.pod perles-02.pod perles-03.pod perles-04.pod perles-05.pod $ perl -le 'print for glob "perles*.pod"' perles-01.pod perles-02.pod perles-03.pod perles-04.pod perles-05.pod
Dans les anciennes version de Perl, cet opérateur était d'ailleurs
implémenté par un appel à csh. Depuis la version 5.6.0 de Perl,
la fonctionnalité est fournie par le module File::Glob
.
En contexte de liste, glob()
renvoie la liste des fichiers
correspondants. En contexte scalaire, glob()
se comporte comme un
itérateur et renvoit un nouveau nom de fichier jusqu'à épuisement
de la liste (à ce moment-là, il renvoie undef
). C'est très utile
dans une boucle while
, par exemple.
Notez que Perl, fidèle à l'esprit DWIM (Do What I Mean), fait ce qu'il
faut dans le cas simple où vous écrivez while(glob"motif")
, puisqu'il
exécute en fait while (defined($_ = glob('motif')))
. Non seulement
il met à jour $_
(encourageant ainsi votre paresse), mais en plus
il vous évitera des problèmes si un fichier nommé 0
existe dans
votre répertoire courant.
Les caractères spéciaux reconnus par glob()
sont :
?
N'importe quel caractère. Exemple : perles-0?.pod
renverrait la liste
complète des fichiers ci-dessus.
*
N'importe quel caractère, 0 fois ou plus. Le classique.
[ ]
Une classe de caractères. Le caractère -
permet de définir une
liste (sauf s'il est utilisé en premier ou en dernier) et le caractère
!
utilisé en premier permet de lister les caractères non désirés.
Exemple : les motifs perles-0[24].pod
et perles-0[!135].pod
renverront tous deux perles-02.pod et perles-04.pod.
{ }
Une liste d'alternatives. Les différentes alternatives sont séparées par
des virgules. Contrairement aux cas précédents (mais exactement comme
en shell), glob()
renvoit alors toutes les possibilités. Ainsi,
perles-0{5,6}.pod
renvoie une liste contenant perl-05.pod et
perl-06.pod, bien que le second fichier n'existe pas.
Tous ces éléments se combinent, bien sûr ; un motif comme
perles-{0,1}{*,4,6}
produira la liste suivante : perles-01.pod,
perles-02.pod, perles-03.pod, perles-04.pod, perles-05.pod,
perles-04.pod, perles-06.pod, perles-14.pod, perles-16.pod.
Le fichier perles-04.pod apparaît deux fois, car il est mentionné
implicitement par *
et explicitement par 4
dans l'alternative.
Comme il n'existe aucun fichier correspondant à perles-1*.pod
, glob()
n'ajoute que les deux fichiers mentionné explicitement.
Le fait que glob()
puisse contruire une liste à partir d'éléments
explicitement donnés m'a été utile pour écrire un script .BAT dans le
cadre de mon travail. Il fallait relancer un script toutes les 5 minutes,
tous les jours et cette installation devait être faite automatiquement par
mon script. La commande at de Windows n'étant pas aussi élaborée que
cron, hélas. Au lieu d'écrire plusieurs boucles foreach
imbriquées,
je me suis contenté d'écrire le motif correspondant à ce que je voulais.
C:\> perl -e '$"=",";print"at $_ every:@{[1..31]} %COMMANDE%\n" for glob qq<{@{["00".."23"]}}:{@{[map{sprintf"%02d",$_*5}0..12]}}>' at 00:00 every:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 %COMMANDE% at 00:05 every:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 %COMMANDE% at 00:10 every:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 %COMMANDE% at 00:15 every:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 %COMMANDE% at 00:20 every:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 %COMMANDE% ...
Je vous laisse décortiquer cet uniligne en guise d'exercice.
glob()
est décrit en détail dans perlop(1), section I/O Operators.
(Philippe "BooK" Bruhat, Paris.pm - book@mongueurs.net
)
Envoyez vos perles à perles@mongueurs.net
, elles seront peut-être
publiées dans un prochain numéro de Linux Magazine.
Copyright © Les Mongueurs de Perl, 2001-2011
pour le site.
Les auteurs conservent le copyright de leurs articles.