
Des codes sources perlConsultez toutes les FAQ
Nombre d'auteurs : 13, nombre de questions : 59, dernière mise à jour : 27 mai 2011
Sommaire
→
Terminal- 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 !!



