Des codes sources perlConsultez toutes les FAQ
Nombre d'auteurs : 13, nombre de questions : 59, dernière mise à jour : 27 mai 2011
- Comment afficher des accents sur une console Windows (DOS) ?
- Comment saisir un mot de passe de façon invisible sur une console ?
- Comment afficher une barre de progression sur une console ?
- Comment créer une question à choix multiple dans un terminal ?
- Comment récupérer proprement les arguments de la ligne de commande ?
Vous avez sans doute déjà rencontré un problème d'affichage d'accents sur une console DOS.
#
!/usr/bin/perl
use strict;
use Carp;
use warnings;
print
"
J
'
essaie
d
'
utiliser
des
accents
àéé\n
"
;
print
"
Essayons
les
entrées
-
sorties
:
\n
"
;
J'essaie d'utiliser des accents ÓÚÚ
Essayons les entrÚes-sorties :
Pour palier à ce désagrément, le système de gestion des encodages de Perl est excellent, puissant et pratique,
mais mal compris par pas mal de gens. Pour afficher les accents correctement sur
la console DOS Windows, Il faut mettre stdout avec l'encodage correct, ou utiliser
l'un des modules spécialisés. chcp permet de récupérer la codepage correcte.
Premièrement, récupérons le codepage correct.
my ($codepage
) =
(`
chcp
`
=
~
m/:\s+(\d+)/
);
Encodons ensuite toutes les sorties STDOUT, STDERR et même STDIN.
Je vous recommande de toujours créer vos scripts au mode utf8. Pour cela, vous devez configurer votre éditeur de texte. Exemple avec PSPAD, il vous suffit de choisir utf8 dans le menu "format". Votre script sera ainsi au format utf8. Ensuite, mettez en début de script :
Voilà, maintenant tout "print" avec accents sera correct dans votre console DOS. Voici un script qui résume les codent ci-dessus qu'on mettra dans une fonction.
#
!/usr/bin/perl
use strict;
use Carp;
use warnings;
use utf8;
ActiverAccentDOS();
print
"
J
'
essaie
d
'
utiliser
des
accents
àéé\n
"
;
print
"
Essayons
les
entrées
-
sorties
:
\n
"
;
sub
ActiverAccentDOS
{
my ($codepage
) =
( `
chcp
`
=
~
m/:\s+(\d+)/
);
foreach my $h
( \*STDOUT, \*STDERR, \*STDIN ) {
binmode
$h
, "
:
encoding
(
cp
$
codepage
)
"
;
}
}
J'essaie d'utiliser des accents àéé
Essayons les entrées-sorties :
C'est quand même beaucoup mieux !! Cette fonction peut être mise dans un de vos modules et appelée en début de vos scripts. Si vous ne souhaitez pas appliquer la modification d'affichage à tout STDOUT, vous pouvez toujours utiliser le module Encode.
#
!/usr/bin/perl
use strict;
use Carp;
use warnings;
use utf8;
use Encode;
my ($codepage
) =
( `
chcp
`
=
~
m/:\s+(\d+)/
);
print
encode("
cp
$
codepage
"
, "
J
'
essaie
d
'
utiliser
des
accents
àéé\n
"
);
print
encode("
cp
$
codepage
"
, "
Essayons
les
entrées
-
sorties
:
\n
"
);
Si vous ne souhaitez pas utiliser le module utf8, il est toujours possible d'utiliser les codes hexa corrects. Faut-il encore s'en souvenir ! Cette solution est moins propre et maintenable, mais peut toujours être utile.
ü | \x81 | à | \x85 | è | \x8A |
é | \x82 | ç | \x87 | ï | \x8B |
â | \x83 | ê | \x88 | î | \x8C |
ä | \x84 | ë | \x89 | ... | ... |
Les informations de ce tableau ont été trouvées
ici,
ce qui nous donne :
#
!/usr/bin/perl
use strict;
use Carp;
use warnings;
print
"
J
'
essaie
d
'
utiliser
des
accents
\x85\x82\x82\n
"
;
print
"
Essayons
les
entr\x82es
-
sorties
:
\n
"
;
Voilà, notez quand même que ce n'est pas très lisible :-) !!
Consultez la discussion sur le forum au sujet des accentsDiscussion sur le forum au sujet des accents.
Pour saisir un mot de passe de façon invisible sur une console DOS, linux ou unix,
il y a un module Perl Term::ReadPasswordTerm::ReadPassword
.
Sous windows, l'auteur du module recommande d'utiliser le module
Term::ReadPassword::Win32Term::ReadPassword::Win32.
#
!/usr/bin/perl
use strict;
use warnings;
use Term::ReadPassword::Win32;
#
Faire
deviner
le
mot
de
passe
:
perl
while (1
) {
my $password
=
read_password('
Veuillez
deviner
le
mot
de
passe
:
'
);
redo unless defined
$password
;
if ($password
eq
'
perl
'
) {
print
"
Bravo
,
c
'
est
le
bon
.
\n
"
;
last;
}
else {
print
"
Dommage
!
\n
"
;
redo;
}
}
#
!/usr/bin/perl
use strict;
use warnings;
use Term::ReadPassword;
#
Faire
deviner
le
mot
de
passe
:
perl
while (1
) {
my $password
=
read_password('
Veuillez
deviner
le
mot
de
passe
:
'
);
redo unless defined
$password
;
if ($password
eq
'
perl
'
) {
print
"
Bravo
,
c
'
est
le
bon
.
\n
"
;
last;
}
else {
print
"
Dommage
!
\n
"
;
redo;
}
}
Pour afficher une barre de progression sur la console DOS, Linux ou Unix, il est possible de la créer soit même ou bien d'utiliser des modules existant. Nous allons vous donner 2 exemples.
- Code conçu soit même
package Progressbar;
use strict;
use warnings;
#
Constructor
sub
new
{
my $proto
=
shift
;
my %p
=
@_
;
my $class
=
ref
($proto
) |
|
$proto
;
my $self
=
{
anim =
>
[ ref
($p
{
anim}
) eq
'
ARRAY
'
?
@{
$
p
{
anim
}
}
: qw(
\\
|
/
-
)
],
text =
>
$p
{
text}
|
|
"
"
,
max =
>
$p
{
max}
|
|
100
,
size =
>
$p
{
size}
|
|
40
,
value =
>
$p
{
init}
|
|
0
,
display_count =
>
$p
{
verbose}
|
|
0
,
animation =
>
$p
{
anim}
|
|
0
,
fill_char =
>
$p
{
fill_char}
|
|
"
#
"
,
nb_filled =
>
0
,
last_size_printed =
>
0
,
}
;
$self
-
>
{
step}
=
$self
-
>
{
max}
/
$self
-
>
{
size}
;
bless
($self
, $class
);
return $self
;
}
#
Progress
method
sub
inc
{
my $self
=
shift
;
my $nb_filled
=
int
(($self
-
>
{
value}
+
+
) /
$self
-
>
{
step}
) +
1
;
if ($self
-
>
{
nb_filled}
!
=
$nb_filled
|
|
$nb_filled
=
=
$self
-
>
{
size}
) {
my $pb
=
sprintf
("
$
self
-
>
{
text
}
[
%
-
$
self
-
>
{
size
}
s
]
"
,
$self
-
>
{
fill_char}
x
$nb_filled
);
$pb
.=
"
"
.$self
-
>
{
anim}
-
>
[$nb_filled
% @{
$
self
->
{
anim
}
}
] if $self
-
>
{
animation}
;
$pb
.=
sprintf
"
%
3d
/
$
self
-
>
{
max
}
"
, $self
-
>
{
value}
if $self
-
>
{
display_count}
;
$pb
.=
"
\r
"
;
print
STDERR $pb
;
$self
-
>
{
last_size_printed}
=
length
$pb
;
}
$self
-
>
{
nb_filled}
=
$nb_filled
;
}
#
Erase
method
sub
erase
{
my $self
=
shift
;
my ($string
) =
@_
;
print
STDERR ("
"
x
$self
-
>
{
last_size_printed}
)."
\r
"
;
print
STDERR $string
if defined
$string
;
}
#
Reset/end
method
sub
end
{
my $self
=
shift
;
$self
-
>
{
value}
=
0
;
$self
-
>
{
nb_filled}
=
0
;
print
STDERR "
\n
"
;
}
1
;
__END__
=head1
NAME
=
head1
SYNOPSIS
use
Progressbar
;
my
$
pb
=
Progressbar
-
>
new
(
text
=
>
"
Computing
"
)
;
foreach
(
0
.
.
99
)
{
#
.
.
.
$
pb
-
>
inc
;
}
$
pb
-
>
erase
(
"
Process
done
"
)
;
$
pb
-
>
end
;
#
$
pb
can
be
re
-
used
immediatly
my
$
pb2
=
Progressbar
-
>
new
(
text
=
>
"
Working
"
,
anim
=
>
1
)
;
my
$
pb3
=
Progressbar
-
>
new
(
text
=
>
"
Working
"
,
max
=
>
1000
,
size
=
>
58
,
init
=
>
500
,
verbose
=
>
1
,
anim
=
>
[
qw
(
0
1
2
3
4
5
6
7
8
9
)
]
,
fill_char
=
>
"
=
"
)
;
foreach
(
0
.
.
99
)
{
#
.
.
.
$
pb2
-
>
inc
;
}
$
pb2
-
>
end
;
foreach
(
500
.
.
999
)
{
#
.
.
.
$
pb3
-
>
inc
;
}
$
pb3
-
>
end
;
=
head1
DESCRIPTION
Prints
a
progress
bar
on
STDERR
using
ASCII
characters
.
=
head1
BUGS
No
known
bug
.
Pour l'utiliser, créez un script test.pl par exemple
#
!/usr/bin/perl
use strict;
use warnings;
use lib "
.
"
;
use Time::HiRes qw(
sleep
)
;
use Progressbar;
my $pb
=
Progressbar-
>
new(text =
>
"
Computing
"
);
foreach (0
.. 99
) {
sleep
(rand
(0
.1
));
$pb
-
>
inc;
}
$pb
-
>
erase("
Process
done
"
);
$pb
-
>
end; #
$pb
can
be
re-used
immediatly
my $pb2
=
Progressbar-
>
new(text =
>
"
Working
"
, anim =
>
1
, verbose =
>
1
);
my $pb3
=
Progressbar-
>
new(text =
>
"
Working
"
,
max =
>
1000
,
size =
>
58
,
init =
>
500
,
verbose =
>
1
,
anim =
>
[qw(
0
1
2
3
4
5
6
7
8
9
)
],
fill_char =
>
"
=
"
);
foreach (0
.. 99
) {
sleep
(rand
(0
.1
));
$pb2
-
>
inc;
}
$pb2
-
>
end;
foreach (500
.. 999
) {
sleep
(rand
(0
.02
));
$pb3
-
>
inc;
}
$pb3
-
>
end;
- Utilisation d'un module existant sur le CPAN Term::ProgressBarTerm::ProgressBar
#
!/usr/bin/perl
use warnings;
use strict;
use Term::ProgressBar;
use Time::HiRes qw(
sleep
)
;
my $MaxValue
=
100
;
my $barre_progression1
=
Term::ProgressBar-
>
new(
{
name =
>
"
[
Computing
]
"
,
count =
>
$MaxValue
,
ETA =
>
"
linear
"
,
}
);
foreach (0
.. $MaxValue
) {
sleep
(rand
(0
.1
));
$barre_progression1
-
>
update($_
);
}
$barre_progression1
-
>
message("
Process
done
"
);
my $barre_progression2
=
Term::ProgressBar-
>
new(
{
name =
>
"
[
Working
]
"
,
count =
>
$MaxValue
,
}
);
foreach (0
.. $MaxValue
) {
sleep
(rand
(0
.1
));
$barre_progression2
-
>
update($_
);
}
$MaxValue
=
1000
;
$barre_progression2
-
>
target($MaxValue
);
$barre_progression2
-
>
message('
max:
1000
'
);
foreach (0
.. $MaxValue
) {
sleep
(rand
(0
.01
));
$barre_progression2
-
>
update($_
);
}
print
"
\nFini
!
"
;
L'utilisation d'une barre de progression peut être intéressant lorsque que
vous lisez un très gros fichier. Ca vous permet de voir l'avancement de la
lecture du fichier. Pour faire cela, il suffit de récupérer la taille du fichier
via stat afin de créer sa barre de progression, puis au fur et à mesure de
la lecture du fichier, de mettre à jour la barre avec la taille courante du
fichier en cours de lecture.
Exemple :
#
!/usr/bin/perl
use warnings;
use strict;
use Term::ProgressBar;
my $file
=
'
mon_fichier.txt
'
;
my $size_max
=
( stat
$file
)[7
];
my ( $compteur_modif
, $progression_octet
, $next_update
) =
( 0
, 0
, 0
);
my $barre_progression
=
Term::ProgressBar-
>
new(
{
name =
>
"
[
Lecture
$
file
]
"
,
count =
>
$size_max
,
ETA =
>
"
linear
"
,
}
);
open
( my $fh
, '
<
'
, $file
) or
die "
Impossible
d
'
ouvrir
le
fichier
$
file
\n
"
;
while ( my $ligne
=
<
$fh
>
) {
#
...
<===
on
travaille
sur
la
ligne
#
bar
$progression_octet
+
=
length
($ligne
);
$next_update
=
$barre_progression
-
>
update($progression_octet
)
if ( $progression_octet
>
$next_update
&
&
$progression_octet
<
$size_max
);
}
close
($fh
);
$barre_progression
-
>
update($size_max
) if $size_max
>=
$next_update
;
Si vous avez besoin que l'utilisateur interagisse avec votre script,
vous avez le choix de le faire via une interface graphique (Perl/Tk, gtk2, etc),
ou via la console (DOS, Linux, Unix, ...).
Pour interagir via une console, on utilise généralement <STDIN>.
C'est simple, mais lorsque l'on a plusieurs choix, on est obligé de faire plusieurs
boucles afin de tester la validité du choix.
De plus, il ne faut pas oublier de faire un chomp pour éliminer les retour chariots.
Il existe une multitude de modules sur le CPAN nous facilitant grandement la vie.
C'est le cas du module
Term::UITerm::UI.
#
!/usr/bin/perl
use warnings;
use strict;
use Term::UI;
use Term::ReadLine;
my $term
=
Term::ReadLine-
>
new('
prompt
'
);
my $reponse
=
$term
-
>
get_reply(
prompt =
>
'
Choisir
un
nombre
:
'
,
choices =
>
[ '
Choix
1
'
, '
Choix
2
'
, '
Choix
3
'
, '
Aucun
choix
'
],
default =
>
'
Aucun
choix
'
,
);
print
"
Vous
avez
choisi
:
$
reponse
\n
"
;
my $bool
=
$term
-
>
ask_yn(
prompt =
>
'
Aimez
vous
les
cookies
?
'
,
default =
>
'
n
'
,
);
if ( $bool
) {
print
"
J
'
aime
les
cookies\n
"
;
}
else {
print
"
Je
n
'
aime
pas
les
cookies\n
"
;
}
On obtient le résultat suivant :
1> Choix 1
2> Choix 2
3> Choix 3
4> Aucun choix
Choisir un nombre : [4]: 7
Invalid selection, please try again: [4] 2
Vous avez choisi : Choix 2
Aimez vous les cookies ? [y/N]: y
J'aime les cookies
Via la méthode get_reply, vous pouvez simuler un QCM facilement et proprement.
Et si vous souhaitez poser une question attendant une réponse yes or no,
c'est encore plus simple avec la méthode ask_yn.
Pour en savoir plus, la documentation CPAN est à votre disposition.
Lorsque vous souhaitez appeler vos scripts perl via une console DOS ou Linux (ou Unix), vous avez souvent besoin de passer des arguments. La manière classique pour les récupérer est d'utiliser la variable @ARGV. Sachez qu'il existe un module perl nous permettant de gérer ces arguments proprement et facilement. Ce module est de plus déjà installé dans le core de perl, c'est le module Getopt::LongGetopt::Long. Voici un exemple de code nous permettant de taper en ligne de commande ceci :
perl script.pl -nom djibril -fichier "C:\repertoire\fichier.txt"
#
!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long;
my ( $nom
, $fichier
) =
();
GetOptions( '
nom=s
'
=
>
\$nom, '
fichier=s
'
=
>
\$fichier,);
if ( defined
$nom
) {
print
"
nom
:
$
nom
\n
"
;
}
if ( defined
$fichier
) {
print
"
fichier
:
$
fichier
\n
"
;
}
nom : djibril
fichier : C:\repertoire\fichier.txt
Ce module est très complet, n'hésitez pas à lire la documentation officielle. Vous pouvez créer des alias, récupérer plusieurs arguments pour une même option, etc. Voici un dernier exemple pour la route !!
perl script.pl -name djibril -fichier "C:\repertoire\fichier.txt" -fichier "D:\repertoire\fichier2.txt" -numero 2 -v
#
!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long;
my ( $nom
, @fichiers
, $numero
, $verbeux
) =
();
GetOptions(
'
nom|name=s
'
=
>
\$nom, #
name
ou
nom
'
fichier=s
'
=
>
\@fichiers, #
On
peut
avoir
plusieurs
fichiers
'
numero=i
'
=
>
\$numero, #
i
pour
integer
=>
on
récupère
un
entier
'
verbeux|v
'
=
>
\$verbeux, #
flag
de
type
-v
ou
-verbeux
ou
--v
ou
--verbeux
);
if ( defined
$nom
) {
print
"
nom
:
$
nom
\n
"
;
}
if ( defined
$numero
) {
print
"
numero
:
$
numero
\n
"
;
}
if ( @fichiers
) {
print
"
fichiers
:
@
fichiers
\n
"
;
}
if ( $verbeux
) {
print
"
mode
verbeux\n
"
;
}
nom : djibril
numero : 2
fichiers : C:\repertoire\fichier.txt D:\repertoire\fichier2.txt
mode verbeux
NB: Notez l'importance de protéger le chemin de vos fichiers par des guillemets, surtout s'il y a des espaces. Voilà, amusez vous bien !!