.\" Automatically generated by Pod::Man 2.09 (Pod::Simple 3.04) .\" .\" Standard preamble: .\" ======================================================================== .de Sh \" Subsection heading .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. | will give a .\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used to .\" do unbreakable dashes and therefore won't be available. \*(C` and \*(C' .\" expand to `' in nroff, nothing in troff, for use with C<>. .tr \(*W-|\(bv\*(Tr .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' 'br\} .\" .\" If the F register is turned on, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . nr % 0 . rr F .\} .\" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .hy 0 .if n .na .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "PERLFAQ8 1" .TH PERLFAQ8 1 "2006-03-26" "DocFr" "User Contributed Perl Documentation" .SH "NAME/NOM" .IX Header "NAME/NOM" perlfaq8 \- Interactions avec le syste\*`me ($Revision: 1.27 $, \f(CW$Date:\fR 2005/12/31 00:54:37 $) .SH "DESCRIPTION" .IX Header "DESCRIPTION" Cette section de la \s-1FAQ\s0 Perl traite des questions concernant les interactions avec le syste\*`me d'exploitation. Cela inclut les me\*'canismes de communication inter-processus (\s-1IPC\s0 \*(-- Inter Process Communication en anglais), le pilotage de l'interface utilisateur (clavier, e\*'cran et souris), et d'une fac\*,on ge\*'ne\*'rale tout ce qui ne rele\*`ve pas de la manipulation de donne\*'es. .PP Lisez les \s-1FAQ\s0 et la documentation spe\*'cifique au portage de perl sur votre syste\*`me d'exploitation (par ex. perlvms, perlplan9, etc.). Vous devriez y trouver de plus amples informations sur les spe\*'cificite\*'s de votre perl. .Sh "Comment savoir sur quel syste\*`me d'exploitation je tourne\ ?" .IX Subsection "Comment savoir sur quel syste`me d'exploitation je tourne?" La variable $^O ($OSNAME si vous utilisez le module English) contient une indication sur le nom du syste\*`me d'exploitation (pas son nume\*'ro de version) sur lequel votre exe\*'cutable perl a e\*'te\*' compile\*'. .Sh "Pourquoi ne revient-on pas apre\*`s un \fIexec()\fP\ ?" .IX Subsection "Pourquoi ne revient-on pas apre`s un exec()?" Parce que c'est ainsi qu'il fonctionne\ : il remplace le processus qui tourne par un nouveau. Si vous voulez continuer apre\*`s (ce qui est probablement le cas si vous vous posez cette question), utilisez pluto\*^t \fIsystem()\fR. .Sh "Comment utiliser le clavier/e\*'cran/souris de fac\*,on e\*'labore\*'e\ ?" .IX Subsection "Comment utiliser le clavier/e'cran/souris de fac,on e'labore'e?" La fac\*,on d'acce\*'der aux (ou de contro\*^ler les) claviers, e\*'crans et souris (\*(L"mulots\*(R") de\*'pend fortement du syste\*`me d'exploitation. Essayez les modules suivants\ : .IP "Clavier" 4 .IX Item "Clavier" .Vb 5 \& Term::Cap Distribution standard \& Term::ReadKey CPAN \& Term::ReadLine::Gnu CPAN \& Term::ReadLine::Perl CPAN \& Term::Screen CPAN .Ve .IP "E\*'cran" 4 .IX Item "E'cran" .Vb 3 \& Term::Cap Distribution standard \& Curses CPAN \& Term::ANSIColor CPAN .Ve .IP "Souris" 4 .IX Item "Souris" .Vb 1 \& Tk CPAN .Ve .PP Certains cas spe\*'cifiques sont examine\*'s sous forme d'exemples dans d'autres re\*'ponses de cette \s-1FAQ\s0. .Sh "Comment afficher quelque chose en couleur\ ?" .IX Subsection "Comment afficher quelque chose en couleur?" En ge\*'ne\*'ral, on ne le fait pas, parce qu'on ne sait pas si le receveur a un afficheur comprenant les couleurs. Cependant, si vous avez la certitude de trouver a\*` l'autre bout un terminal \s-1ANSI\s0 qui traite la couleur, vous pouvez utiliser le module Term::ANSIColor de \s-1CPAN\s0\ : .PP .Vb 3 \& use Term::ANSIColor; \& print color("red"), "Stop!\en", color("reset"); \& print color("green"), "Go!\en", color("reset"); .Ve .PP Ou comme ceci\ : .PP .Vb 3 \& use Term::ANSIColor qw(:constants); \& print RED, "Stop!\en", RESET; \& print GREEN, "Go!\en", RESET; .Ve .ie n .Sh "Comment lire simplement une touche sans attendre un appui sur ""entre\*'e""\ ?" .el .Sh "Comment lire simplement une touche sans attendre un appui sur ``entre\*'e''\ ?" .IX Subsection "Comment lire simplement une touche sans attendre un appui sur entre'e?" Le contro\*^le des tampons en entre\*'e est fortement de\*'pendant du syste\*`me. Sur la plupart d'entre eux, vous pouvez simplement utiliser la commande \fBstty\fR comme montre\*' dans \*(L"getc\*(R" in perlfunc, mais visiblement, cela vous entrai\*^ne de\*'ja\*` dans les me\*'andres de la portabilite\*'. .PP .Vb 6 \& open(TTY, "+/dev/tty 2>&1"; \& $key = getc(TTY); # peut marcher \& # OU BIEN \& sysread(TTY, $key, 1); # marche sans doute \& system "stty \-cbreak /dev/tty 2>&1"; .Ve .PP Le module Term::ReadKey de \s-1CPAN\s0 offre une interface pre\*^te a\*` l'emploi, et devrait e\*^tre plus efficace que de lancer des \fBstty\fR pour chaque touche. Il inclut me\*^me un support limite\*' pour Windows. .PP .Vb 4 \& use Term::ReadKey; \& ReadMode('cbreak'); \& $key = ReadKey(0); \& ReadMode('normal'); .Ve .PP Cependant, cela requiert que vous ayez un compilateur C fonctionnel, qui puisse e\*^tre utilise\*' pour compiler et installer des modules de \&\s-1CPAN\s0. Voici une solution n'utilisant que le module standard \s-1POSIX\s0, qui devrait e\*^tre disponible en natif sur votre syste\*`me (s'il est lui\-me\*^me \&\s-1POSIX\s0). .PP .Vb 2 \& use HotKey; \& $key = readkey(); .Ve .PP Et voici le module HotKey, qui cache les appels \s-1POSIX\s0 ge\*'rant les structures termios, qui sont assez e\*'sote\*'riques, il faut bien l'avouer\ : .PP .Vb 2 \& # HotKey.pm \& package HotKey; \& \& @ISA = qw(Exporter); \& @EXPORT = qw(cbreak cooked readkey); \& \& use strict; \& use POSIX qw(:termios_h); \& my ($term, $oterm, $echo, $noecho, $fd_stdin); \& \& $fd_stdin = fileno(STDIN); \& $term = POSIX::Termios\->new(); \& $term\->getattr($fd_stdin); \& $oterm = $term\->getlflag(); \& \& $echo = ECHO | ECHOK | ICANON; \& $noecho = $oterm & ~$echo; \& \& sub cbreak { \& $term\->setlflag($noecho); # ok, on ne veut pas d'e\*'cho non plus \& $term\->setcc(VTIME, 1); \& $term\->setattr($fd_stdin, TCSANOW); \& } \& \& sub cooked { \& $term\->setlflag($oterm); \& $term\->setcc(VTIME, 0); \& $term\->setattr($fd_stdin, TCSANOW); \& } \& \& sub readkey { \& my $key = ''; \& cbreak(); \& sysread(STDIN, $key, 1); \& cooked(); \& return $key; \& } \& \& END { cooked() } \& \& 1; .Ve .Sh "Comment ve\*'rifier si des donne\*'es sont en attente depuis le clavier\ ?" .IX Subsection "Comment ve'rifier si des donne'es sont en attente depuis le clavier?" Le moyen le plus facile pour cela est de lire une touche en mode non bloquant, en utilisant le module Term::ReadKey de \s-1CPAN\s0, et en lui passant un argument de \-1 pour indiquer ce fait. .PP .Vb 1 \& use Term::ReadKey; \& \& ReadMode('cbreak'); \& \& if (defined ($char = ReadKey(\-1)) ) { \& # il y avait un caracte\*`re disponible, maintenant dans $char \& } else { \& # pas de touche presse\*'e pour l'instant \& } \& \& ReadMode('normal'); # restaure le terminal en mode normal .Ve .Sh "Comment effacer l'e\*'cran\ ?" .IX Subsection "Comment effacer l'e'cran?" Si vous devez le faire de fac\*,on occasionnelle, utilisez \f(CW\*(C`system\*(C'\fR\ : .PP .Vb 1 \& system("clear"); .Ve .PP Si ce doit e\*^tre une ope\*'ration fre\*'quente, sauvegardez la se\*'quence de nettoyage pour pouvoir ensuite l'afficher 100 fois sans avoir a\*` appeler un programme externe autant de fois\ : .PP .Vb 2 \& $clear_string = `clear`; \& print $clear_string; .Ve .PP Si vous pre\*'voyez d'autres manipulations d'e\*'cran, comme le positionnement du curseur, etc., utilisez pluto\*^t le module Term::Cap\ : .PP .Vb 3 \& use Term::Cap; \& $terminal = Term::Cap\->Tgetent( {OSPEED => 9600} ); \& $clear_string = $terminal\->Tputs('cl'); .Ve .Sh "Comment obtenir la taille de l'e\*'cran\ ?" .IX Subsection "Comment obtenir la taille de l'e'cran?" Si vous avez le module Term::ReadKey de \s-1CPAN\s0, vous pouvez l'utiliser pour re\*'cupe\*'rer la hauteur et la largeur en caracte\*`res et en pixels: .PP .Vb 2 \& use Term::ReadKey; \& ($wchar, $hchar, $wpixels, $hpixels) = GetTerminalSize(); .Ve .PP Cela est plus portable qu'un appel direct a\*` \f(CW\*(C`ioctl\*(C'\fR, mais n'est pas aussi illustratif\ : .PP .Vb 10 \& require 'sys/ioctl.ph'; \& die "no TIOCGWINSZ " unless defined &TIOCGWINSZ; \& open(TTY, "+autoflush(1); .Ve .Sp Comme explique\*' dans le point pre\*'ce\*'dent, cela ne marchera pas si vous utilisez des E/S sur une prise entre Unix et un Macintosh. Vous devrez ca\*^bler vos terminaisons de ligne, dans ce cas. .IP "entre\*'e non bloquante" 4 .IX Item "entre'e non bloquante" Si vous effectuez une lecture bloquante par \fIread()\fR ou \fIsysread()\fR, vous devrez vous arranger pour que le de\*'clenchement d'une alarme vous fournisse le de\*'blocage ne\*'cessaire (voir \*(L"alarm\*(R" in perlfunc). Si vous avez effectue\*' une ouverture non bloquante, vous be\*'ne\*'ficierez certainement d'une lecture non bloquante, ce qui peut forcer l'utilisation de \fIselect()\fR (dans sa version avec 4 arguments), pour de\*'terminer si l'E/S est possible ou non sur ce pe\*'riphe\*'rique (voir \&\*(L"select\*(R" in perlfunc.) .PP En cherchant a\*` lire sa boi\*^te vocale, le fameux Jamie Zawinski , apre\*`s de nombreux grincements de dents et une lutte avec sysread, sysopen, les caprices de la fonction \s-1POSIX\s0 tcgetattr, et de nombreuses autres fonctions promettant de s'e\*'clater la nuit, est finalement arrive\*' a\*` ceci\ : .PP .Vb 10 \& sub open_modem { \& use IPC::Open2; \& my $stty = `/bin/stty \-g`; \& open2( \e*MODEM_IN, \e*MODEM_OUT, "cu \-l$modem_device \-s2400 2>&1"); \& # lancer cu trafique les parame\*`tres de /dev/tty, me\*^me lorsqu'il a \& # e\*'te\*' lance\*' depuis un tube... \& system("/bin/stty $stty"); \& $_ = ; \& chomp; \& if ( !m/^Connected/ ) { \& print STDERR "$0: cu printed `$_' instead of `Connected'\en"; \& } \& } .Ve .Sh "Comment de\*'coder les fichiers de mots de passe crypte\*'s\ ?" .IX Subsection "Comment de'coder les fichiers de mots de passe crypte's?" En de\*'pensant d'e\*'normes quantite\*'s d'argent pour du mate\*'riel de\*'die\*', mais cela finira par attirer l'attention. .PP Se\*'rieusement, cela n'est pas possible si ce sont des mots de passe Unix \*(-- le syste\*`me de cryptage des mots de passe sur Unix utilise une fonction de hachage a\*` sens unique. C'est plus du hachage que de l'encryption. La meilleure me\*'thode consiste a\*` trouver quelque chose d'autre qui se hache de la me\*^me fac\*,on. Il n'est pas possible d'inverser la fonction pour retrouver la chai\*^ne d'origine. Des programmes comme Crack peuvent essayer de deviner les mots de passe de fac\*,on brutale (et fute\*'e), mais ne vont pas (ne peuvent pas) garantir de succe\*`s rapide. .PP Si vous avez peur que vos utilisateurs ne choisissent de mauvais mots de passe, vous devriez le ve\*'rifier au vol lorsqu'ils essaient de changer leur mot-de-passe (en modifiant la commande \fIpasswd\fR\|(1) par exemple). .Sh "Comment lancer un processus en arrie\*`re plan\ ?" .IX Subsection "Comment lancer un processus en arrie`re plan?" Plusieurs modules savent lancer d'autres processus sans bloquer votre prorgamme Perl. Vous pouvez utiliser IPC::Open3, Parallel::Jobs, IPC::Run et quelques-uns des modules \s-1POE\s0. Voir \s-1CPAN\s0 pour plus de de\*'tails. .PP Vous pouvez aussi utiliser .PP .Vb 1 \& system("cmd &") .Ve .PP ou utiliser fork comme explique\*' dans \*(L"fork\*(R" in perlfunc, avec des exemples supple\*'mentaires dans perlipc. Voici quelques petites choses dont il vaut mieux e\*^tre conscient sur un syste\*`me de type Unix: .IP "\s-1STDIN\s0, \s-1STDOUT\s0, et \s-1STDERR\s0 sont partage\*'s." 4 .IX Item "STDIN, STDOUT, et STDERR sont partage's." Le processus principal et celui en arrie\*`re plan (le processus \*(L"fils\*(R") partagent les me\*^mes descripteurs de fichier \s-1STDIN\s0, \s-1STDOUT\s0 et \s-1STDERR\s0. Si les deux essaient d'y acce\*'der en me\*^me temps, d'e\*'tranges phe\*'nome\*`nes peuvent survenir. Il vaudrait mieux les fermer ou les re\*'ouvir dans le fils. On peut contourner ce fait en ouvrant un tube via \f(CW\*(C`open\*(C'\fR (voir \*(L"open\*(R" in perlfunc) mais sur certains syste\*`mes, cela implique que le processus fils ne puisse pas survivre a\*` son pe\*`re. .IP "Signaux" 4 .IX Item "Signaux" Il faudra capturer les signaux \s-1SIGCHLD\s0, et peut e\*^tre \s-1SIGPIPE\s0 aussi. Un \s-1SIGCHLD\s0 est envoye\*' lorsque le processus en arrie\*`re plan se termine. Un \s-1SIGPIPE\s0 est envoye\*' lorsque l'on e\*'crit dans un descripteur de fichier que le processus fils a ferme\*' (ne pas capturer un \s-1SIGPIPE\s0 peut causer silencieusement la mort du processus). Cela n'est pas un proble\*`me avec \f(CW\*(C`system("cmd&")\*(C'\fR. .IP "Zombies" 4 .IX Item "Zombies" Il faut vous pre\*'parer a\*` \*(L"collecter\*(R" les processus fils qui se terminent\ : .Sp .Vb 1 \& $SIG{CHLD} = sub { wait }; \& \& $SIG{CHLD} = 'IGNORE'; .Ve .Sp Voous pouvez aussi utiliser la technique du double fork. Vous faites un \fIwait()\fR imme\*'diat de votre fils et c'est le daemon init qui fera le \&\fIwait()\fR de votre petit-fils lorsqu'il se terminera. .Sp .Vb 8 \& unless ($pid = fork) { \& unless (fork) { \& exec "ce que vous voulez re\*'ellement faire"; \& die "e\*'chec d'exec !"; \& } \& exit 0; \& } \& waitpid($pid,0); .Ve .Sp Voir \*(L"Signaux\*(R" in perlipc pour d'autres exemple de code re\*'alisant cela. Il n'est pas possible d'obtenir des zombies avec \f(CW\*(C`system("prog &")\*(C'\fR. .Sh "Comment capturer un caracte\*`re de contro\*^le, un signal\ ?" .IX Subsection "Comment capturer un caracte`re de contro^le, un signal?" On ne \*(L"capture\*(R" (en anglais \*(L"trap\*(R") pas vraiment un caracte\*`re de contro\*^le. En fait, ce caracte\*`re ge\*'ne\*`re un signal qui est envoye\*' au groupe du terminal sur lequel tourne le processus en avant plan, signal que l'on capture ensuite dans le processus. Les signaux sont documente\*'s dans \*(L"Signaux\*(R" in perlipc et dans le chapitre \*(L"Signaux\*(R" du Camel Book. .PP Vous pouvez utiliser la table de hachage \f(CW%SIG\fR pour y attacher vos fonctions de gestion des signaux. Lorsque perl rec\*,oit un signal, il cherche dans \f(CW%SIG\fR une cle\*' identique au nom du signal rec\*,u et appelle la fonction associe\*'e a\*` cette cle\*'. .PP .Vb 1 \& # via un sous\-programme anonyme \& \& $SIG{INT} = sub { syswrite(STDERR, "ouch\en", 5 ) }; \& \& # via une re\*'fe\*'rence a\*` une fonction \& \& $SIG{INT} = \e&ouch; \& \& # via une chai\*^ne content le nom de la fonction \& # (re\*'fe\*'rence symbolique) \& \& $SIG{INT} = "ouch"; .Ve .PP Dans les versions de Perl ante\*'rieures a\*` 5.8, le signal e\*'tait traite\*' de\*`s sa re\*'ception via du code C qui captait le signal et appelait directement une e\*'ventuelle fonction Perl stocke\*'e dans \f(CW%SIG\fR. Cela pouvait amener perl a plante\*'. Depuis la version 5.8.0, perl regarde dans \f(CW%SIG\fR *apre\*`s* la re\*'ception du signal, et non au moment de sa re\*'ception. Les versions ante\*'rieures de cette re\*'ponse e\*'taient errone\*'es. .Sh "Comment modifier le fichier masque\*' (shadow) de mots de passe sous Unix\ ?" .IX Subsection "Comment modifier le fichier masque' (shadow) de mots de passe sous Unix?" Si perl a e\*'te\*' installe\*' correctement et que votre librairie d'acce\*`s au fichier masque\*' est e\*'crite proprement, alors les fonctions getpw*() de\*'crites dans perlfunc devraient, en the\*'orie, fournir un acce\*`s (en lecture seule) aux mots de passe masque\*'s. Pour changer le fichier, faites une copie du fichier de masque (son format varie selon les syste\*`mes \- voir \fIpasswd\fR\|(5) pour les de\*'tails) et utilisez \fIpwd_mkdb\fR\|(8) pour l'installer (voir pwd_mkdb pour plus de de\*'tails). .Sh "Comment positionner l'heure et la date\ ?" .IX Subsection "Comment positionner l'heure et la date?" En supposant que vous tourniez avec des privile\*`ges suffisants, vous devriez e\*^tre capables de changer l'heure du syste\*`me et le temps en lanc\*,ant la commande \fIdate\fR\|(1). (Il n'y a pas moyen de positionner l'heure et la date pour un processus seulement.) Ce me\*'canisme fonctionnera sous Unix, \s-1MS\-DOS\s0, Windows et \s-1NT\s0\ ; sous \s-1VMS\s0 une commande e\*'quivalente est \f(CW\*(C`set time\*(C'\fR. .PP Si par contre vous de\*'sirez seulement changer de fuseau horaire, vous pourrez certainement vous en sortir en positionnant une variable d'environnement\ : .PP .Vb 3 \& $ENV{TZ} = "MST7MDT"; # unixien \& $ENV{'SYS$TIMEZONE_DIFFERENTIAL'}="\-5" # vms \& system "trn comp.lang.perl.misc"; .Ve .Sh "Comment effectuer un \fIsleep()\fP ou \fIalarm()\fP de moins d'une seconde\ ?" .IX Subsection "Comment effectuer un sleep() ou alarm() de moins d'une seconde?" Pour obtenir une granularite\*' plus fine que la seconde obtenue par la fonction \fIsleep()\fR, le plus simple est d'utiliser \fIselect()\fR comme de\*'crit dans \*(L"select\*(R" in perlfunc. Essayez aussi les modules Time::HiRes et BSD::Itimer (disponibles sur \s-1CPAN\s0 et dans la distribution standard depuis Perl 5.8 pour Time::HiRes). .Sh "Comment mesurer un temps infe\*'rieur a\*` une seconde\ ?" .IX Subsection "Comment mesurer un temps infe'rieur a` une seconde?" En ge\*'ne\*'ral, cela risque d'e\*^tre difficile. Le module Time::HiRes (disponible sur \s-1CPAN\s0 et dans la distribution standard depuis Perl 5.8) apporte cette fonctionnalite\*' sur certains syste\*`mes. .PP Si votre syste\*`me supporte a\*` la fois la fonction \fIsyscall()\fR en Perl et un appel syste\*`me tel que \fIgettimeofday\fR\|(2), alors vous pouvez peut\-e\*^tre faire quelque chose comme ceci\ : .PP .Vb 1 \& require 'sys/syscall.ph'; \& \& $TIMEVAL_T = "LL"; \& \& $done = $start = pack($TIMEVAL_T, ()); \& \& syscall(&SYS_gettimeofday, $start, 0) != \-1 \& or die "gettimeofday: $!"; \& \& ############################# \& # FAITES VOS OPERATIONS ICI # \& ############################# \& \& syscall( &SYS_gettimeofday, $done, 0) != \-1 \& or die "gettimeofday: $!"; \& \& @start = unpack($TIMEVAL_T, $start); \& @done = unpack($TIMEVAL_T, $done); \& \& # corriger les microsecondes \& for ($done[1], $start[1]) { $_ /= 1_000_000 } \& \& $delta_time = sprintf "%.4f", ($done[0] + $done[1] ) \& \- \& ($start[0] + $start[1] ); .Ve .Sh "Comment re\*'aliser un \fIatexit()\fP ou \fIsetjmp()\fP/\fIlongjmp()\fP\ ? (traitement d'exceptions)" .IX Subsection "Comment re'aliser un atexit() ou setjmp()/longjmp()? (traitement d'exceptions)" La version 5 de Perl apporte le bloc \s-1END\s0, qui peut e\*^tre utilise\*' pour simuler \fIatexit()\fR. Le bloc \s-1END\s0 de chaque paquetage est appele\*' lorsque le programme ou le fil d'exe\*'cution se termine (voir la page perlmod pour plus de details). .PP Par exemple, on peut utiliser ceci pour s'assurer qu'un programme filtre est bien parvenu a\*` vider son tampon de sortie sans remplir tout le disque\ : .PP .Vb 3 \& END { \& close(STDOUT) || die "stdout close failed: $!"; \& } .Ve .PP Par contre, le bloc \s-1END\s0 n'est pas appele\*' lorsqu'un signal non capture\*' tue le programme, donc si vous utilisez les blocs \s-1END\s0, vous devriez aussi utiliser\ : .PP .Vb 1 \& use sigtrap qw(die normal\-signals); .Ve .PP En Perl, le traitement des exceptions s'effectue au travers de l'ope\*'ration \fIeval()\fR. Vous pouvez utiliser \fIeval()\fR en lieu et place de setjmp, et \fIdie()\fR pour \fIlongjmp()\fR. Pour plus de de\*'tails sur cela, lire la section sur les signaux, et plus particulie\*`rement le traitement limitant le temps de blocage pour un \fIflock()\fR dans \*(L"Signaux\*(R" in perlipc et le chapitre \*(L"Sigaux\*(R" du Camel Book. .PP Si tout ce qui vous inte\*'resse est le traitement des exceptions proprement dit, essayez la bibliothe\*`que exceptions.pl (qui fait partie de la distribution standard de Perl). .PP Si vous pre\*'fe\*'rez la syntaxe de \fIatexit()\fR (et de\*'sirez \fIrmexit()\fR aussi), essayez le module AtExit disponible sur \s-1CPAN\s0. .Sh "Pourquoi mes programmes avec \fIsocket()\fP ne marchent pas sous System V (Solaris)\ ? Que signifie le message d'erreur X\ Protocole non supporte\*'\ X\ ?" .IX Subsection "Pourquoi mes programmes avec socket() ne marchent pas sous System V (Solaris)? Que signifie le message d'erreur XProtocole non supporte'X?" Certains syste\*`mes base\*'s sur Sys\-V, et particulie\*`rement Solaris 2.X, ont rede\*'fini certaines constantes lie\*'e aux prises (sockets) et qui e\*'taient des standards de fait. E\*'tant donne\*' que ces constantes e\*'taient communes sur toutes les architectures, elles e\*'taient souvent ca\*^ble\*'es dans le code perl. La bonne manie\*`re de re\*'soudre ce proble\*`me est d'utiliser \*(L"use Socket\*(R" pour obtenir les valeurs correctes. .PP Notez que bien que SunOS et Solaris soient compatibles au niveau des binaires, ces valeurs sont ne\*'anmoins diffe\*'rentes. Allez comprendre\ ! .Sh "Comment appeler les fonctions C spe\*'cifiques a\*` mon syste\*`me depuis Perl\ ?" .IX Subsection "Comment appeler les fonctions C spe'cifiques a` mon syste`me depuis Perl?" Dans la plupart des cas, on e\*'crit un module externe \*(-- voir la re\*'ponse a\*` la question \*(L"Ou\*` puis-je apprendre a\*` lier du C avec Perl? [h2xs, xsubpp]\*(R". Cependant, si la fonction est un appel syste\*`me et que votre syste\*`me supporte \fIsyscall()\fR, vous pouvez l'utiliser pour ce faire (documente\*'e dans perlfunc). .PP Rappelez-vous de regarder les modules qui sont livre\*'s avec votre distribution, ainsi que ceux disponibles sur \s-1CPAN\s0 \- quelqu'un a peut\-e\*^tre deja e\*'crit un module pour le faire. Sur Windows, essayez Win32::API. Sur Mac, essayez Mac::Carbon. Si aucun module ne propose d'interface vers cette fonction C, vous pouvez inse\*'rez un peu de code C directement dans votre code Perl via le module Inline::C. .Sh "Ou\*` trouver les fichiers d'inclusion pour \fIioctl()\fP et \fIsyscall()\fP\ ?" .IX Subsection "Ou` trouver les fichiers d'inclusion pour ioctl() et syscall()?" Historiquement, ceux-ci sont ge\*'ne\*'re\*'s par l'outil h2ph, inclus dans les distributions standard de perl. Ce programme convertit les directives \&\fIcpp\fR\|(1) du fichier d'inclusion C en un fichier contenant des de\*'finitions de sous\-routines, comme &SYS_getitimer, qui peuvent ensuite e\*^tre utilise\*'es comme argument de vos fonctions. Cela ne fonctionne pas parfaitement, mais l'essentiel du travail est fait. Des fichiers simples comme \fIerrno.h\fR, \fIsyscall.h\fR, et \fIsocket.h\fR donnent de bons re\*'sultats, mais de plus complexes comme \fIioctl.h\fR demandent presque toujours une intervention manuelle apre\*`s coup. Voici comment installer les fichiers *.ph: .PP .Vb 3 \& 1. devenir super\-utilisateur \& 2. cd /usr/include \& 3. h2ph *.h */*.h .Ve .PP Si votre syste\*`me supporte le chargement dynamique, et pour des raisons de portabilite\*' et de sanite\*', vous devriez pluto\*^t utiliser h2xs (qui fait lui aussi partie de la distribution standard de perl). Cet outil convertit un fichier d'inclusion C en une extension Perl. Voir perlxstut pour savoir comment de\*'buter avec h2xs. .PP Si votre syste\*`me ne support pas le chargement dynamique, vous pouvez ne\*'anmoins utiliser h2xs. Voir perlxstut et ExtUtils::MakeMaker pour plus d'information (brie\*`vement, utilisez simplement \fBmake perl\fR et non un simple \fBmake\fR pour reconstruire un perl avec une nouvelle extension statiquement lie\*'e). .Sh "Pourquoi les scripts perl en setuid se plaignent-ils d'un proble\*`me noyau\ ?" .IX Subsection "Pourquoi les scripts perl en setuid se plaignent-ils d'un proble`me noyau?" Certains syste\*`mes d'exploitation ont un bug dans leur noyau qui rend les scripts setuid [\s-1NDT\s0\ : fichiers dont le bit 's' est positionne\*' sur l'exe\*'cutable, par exemple avec \*(L"chmod u+s\*(R" sous Unix] non su\*^rs intrinse\*`quement. Perl vous offre quelques options (de\*'crites dans perlsec) pour contourner ce fait sur ces syste\*`mes. .Sh "Comment ouvrir un tube depuis et vers une commande simultane\*'ment\ ?" .IX Subsection "Comment ouvrir un tube depuis et vers une commande simultane'ment?" Le module IPC::Open2 (qui fait partie de la distribution perl standard) est une approche aise\*'e qui utilise en interne les appels syste\*`mes \fIpipe()\fR, \fIfork()\fR et \fIexec()\fR. Cependant, soyez su\*^rs de bien lire les avertissements concernant les interblocages dans sa documentation (voir IPC::Open2). Voir aussi \*(L"Communication bidirectionnelle avec un autre processus\*(R" in perlipc et \*(L"Communication bidirectionnelle avec vous\-me\*^me\*(R" in perlipc. .PP On peut aussi utiliser le module IPC:Open3 (lui aussi dans la distribution standard), mais attention: l'ordre des arguments est diffe\*'rent de celui utilise\*' par IPC::Open2 (voir IPC::Open3). .Sh "Pourquoi ne puis-je pas obtenir la sortie d'une commande avec \fIsystem()\fP\ ?" .IX Subsection "Pourquoi ne puis-je pas obtenir la sortie d'une commande avec system()?" Vous confondez \fIsystem()\fR avec les apostrophes inverse\*'es (backticks, ``). La fonction \fIsystem()\fR lance une commande et retourne sa valeur de sortie (une valeur sur 16 bits\ : les 7 bits de poids faible indiquent le signal qui a tue\*' le processus le cas e\*'che\*'ant, et les 8 bits de poids fort sont la valeur de sortie effective). Les apostrophes inverse\*'es (``) lancent une commande et retournent ce que cette commande a e\*'mis sur \s-1STDOUT\s0. .PP .Vb 2 \& $exit_status = system("mail\-users"); \& $output_string = `ls`; .Ve .Sh "Comment capturer la sortie \s-1STDERR\s0 d'une commande externe\ ?" .IX Subsection "Comment capturer la sortie STDERR d'une commande externe?" Il y a trois moyens fondamentaux de lancer une commande externe\ : .PP .Vb 3 \& system $cmd; # avec system() \& $output = `$cmd`; # avec les apostrophes inverse\*'es (``) \& open (PIPE, "cmd |"); # avec open() .Ve .PP Avec \fIsystem()\fR, \s-1STDOUT\s0 et \s-1STDERR\s0 vont tous deux aller la\*` ou\*` ces descripteurs sont dirige\*'s dans le script lui\-me\*^me, sauf si la commande \&\fIsystem()\fR les redirige exiplicitement par ailleurs. Les apostrophes inverse\*'es et \fIopen()\fR lisent \fBuniquement\fR la sortie (\s-1STDOUT\s0) de votre commande externe. .PP Vous pouvez aussi utiliser la fonction \fIopen3()\fR du module IPC::Open3. Benjamin Goldberg propose les quelques exemples de code suivants. .PP Pour re\*'cupe\*'rer le \s-1STDOUT\s0 de votre programme externe et se de\*'barrasser de son \s-1STDERR\s0\ : .PP .Vb 7 \& use IPC::Open3; \& use File::Spec; \& use Symbol qw(gensym); \& open(NULL, ">", File::Spec\->devnull); \& my $pid = open3(gensym, \e*PH, ">&NULL", "cmd"); \& while( ) { } \& waitpid($pid, 0); .Ve .PP Pour re\*'cupe\*'rer le \s-1STDERR\s0 de votre programme externe et se de\*'barrasser de son \s-1STDOUT\s0\ : .PP .Vb 7 \& use IPC::Open3; \& use File::Spec; \& use Symbol qw(gensym); \& open(NULL, ">", File::Spec\->devnull); \& my $pid = open3(gensym, ">&NULL", \e*PH, "cmd"); \& while( ) { } \& waitpid($pid, 0); .Ve .PP Pour re\*'cupe\*'rer le \s-1STDERR\s0 de votre programme externe, et rediriger son \&\s-1STDOUT\s0 vers votre propre \s-1STDERR\s0\ : .PP .Vb 5 \& use IPC::Open3; \& use Symbol qw(gensym); \& my $pid = open3(gensym, ">&STDERR", \e*PH, "cmd"); \& while( ) { } \& waitpid($pid, 0); .Ve .PP Pour re\*'cupe\*'rer se\*'pare\*'ment le \s-1STDOUT\s0 et le \s-1STDERR\s0 de vote commande externe, vous pouvez les rediriger vers des fichiers temporaires, exe\*'cuter la commande puis lire les fichiers temporaires\ : .PP .Vb 10 \& use IPC::Open3; \& use Symbol qw(gensym); \& use IO::File; \& local *CATCHOUT = IO::File\->new_tmpfile; \& local *CATCHERR = IO::File\->new_tmpfile; \& my $pid = open3(gensym, ">&CATCHOUT", ">&CATCHERR", "cmd"); \& waitpid($pid, 0); \& seek $_, 0, 0 for \e*CATCHOUT, \e*CATCHERR; \& while( ) {} \& while( ) {} .Ve .PP Mais les *deux* fichiers temporaires ne sont pas absolument indispensables. Le code suivant fonctionnera aussi bien, sans interblocage\ : .PP .Vb 9 \& use IPC::Open3; \& use Symbol qw(gensym); \& use IO::File; \& local *CATCHERR = IO::File\->new_tmpfile; \& my $pid = open3(gensym, \e*CATCHOUT, ">&CATCHERR", "cmd"); \& while( ) {} \& waitpid($pid, 0); \& seek CATCHERR, 0, 0; \& while( ) {} .Ve .PP Et il sera aussi plus rapide puisque vous pourrez traiter la sortie du programme imme\*'diatement pluto\*^t que d'attendre la terminaison du programme. .PP Avec toutes ces routines, vous pouvez changer les descripteurs de fichier avant l'appel\ : .PP .Vb 2 \& open(STDOUT, ">logfile"); \& system("ls"); .Ve .PP ou vous pouvez utiliser les redirections du shell de Bourne\ : .PP .Vb 2 \& $output = `$cmd 2>some_file\*`; \& open (PIPE, "cmd 2>some_file |"); .Ve .PP Vous pouvez aussi utiliser les redirections de fichier pour rendre \&\s-1STDERR\s0 un synonyme de \s-1STDOUT\s0\ : .PP .Vb 2 \& $output = `$cmd 2>&1`; \& open (PIPE, "cmd 2>&1 |"); .Ve .PP Cependant, vous ne \fIpouvez pas\fR simplement ouvrir \s-1STDERR\s0 en synonyme de \s-1STDOUT\s0 depuis votre programme Perl, et ne pas recourir ensuite a\*` la redirection en shell. Ceci ne marche pas\ : .PP .Vb 2 \& open(STDERR, ">&STDOUT"); \& $alloutput = `cmd args`; # stderr n'est toujours pas capture\*' .Ve .PP Cela e\*'choue parce que \fIopen()\fR rend \s-1STDERR\s0 un synonyme de \s-1STDOUT\s0 au moment ou\*` l'appel a\*` \fIopen()\fR a e\*'te\*' effectue\*'. Les apostrophes inverse\*'es redirigent ensuite \s-1STDOUT\s0 vers une chai\*^ne, mais ne changent pas \s-1STDERR\s0 (qui va toujours la\*` ou\*` allait le \s-1STDOUT\s0 d'origine). .PP Notez bien que vous \fIdevez\fR utiliser la syntaxe de redirection du shell de Bourne (\fIsh\fR\|(1)), et non celle de \fIcsh\fR\|(1)\ ! Des pre\*'cisions sur les raisons pour lesquelles Perl utilise le shell de Bourne pour \&\fIsystem()\fR et les apostrophes inverse\*'es, ainsi que lors des ouvertures de tubes, se trouvent dans l'article \fIversus/csh.whynot\fR de la collection \*(L"Far More Than You Ever Wanted To Know\*(R" sur . .PP Pour capturer a\*` la fois le \s-1STDOUT\s0 et le \s-1STDERR\s0 d'une commande\ : .PP .Vb 3 \& $output = `cmd 2>&1`; # soit avec des apostrophes \& $pid = open(PH, "cmd 2>&1 |"); # inverse\*'es, soit avec un tube \& while () { } # plus une lecture .Ve .PP Pour capturer seulement le \s-1STDOUT\s0 et jeter le \s-1STDERR\s0 d'une commande\ : .PP .Vb 3 \& $output = `cmd 2>/dev/null`; # soit avec des apostrophes \& $pid = open(PH, "cmd 2>/dev/null |"); # inverse\*'es, soit avec un tube \& while () { } # plus une lecture .Ve .PP Pour capturer seulement le \s-1STDERR\s0 et jeter le \s-1STDOUT\s0 d'une commande\ : .PP .Vb 3 \& $output = `cmd 2>&1 1>/dev/null`; # soit avec des apostrophes \& $pid = open(PH, "cmd 2>&1 1>/dev/null |"); # inverse\*'es, soit avec un tube \& while () { } # plus une lecture .Ve .PP Pour e\*'changer le \s-1STDOUT\s0 et le \s-1STDERR\s0 d'une commande afin d'en capturer le \s-1STDERR\s0 mais laisser le \s-1STDOUT\s0 sortir a\*` la place du \s-1STDERR\s0 d'origine\ : .PP .Vb 3 \& $output = `cmd 3>&1 1>&2 2>&3 3>&\-`; # soit avec des apostrophes \& $pid = open(PH, "cmd 3>&1 1>&2 2>&3 3>&\-|");# inverse\*'es, soit avec un tube \& while () { } # plus une lecture .Ve .PP Pour lire se\*'pare\*'ment le \s-1STDOUT\s0 et le \s-1STDERR\s0 d'une commande, il est plus facile de les rediriger chacun dans un fichier, et ensuite de les lire lorsque la commande est termine\*'e\ : .PP .Vb 1 \& system("program args 1>program.stdout 2>program.stderr"); .Ve .PP L'ordre est important dans tout ces exemples. Cela est du\*^ au fait que le shell prend toujours en compte les redirections en les lisant strictement de gauche a\*` droite. .PP .Vb 2 \& system("prog args 1>tmpfile 2>&1"); \& system("prog args 2>&1 1>tmpfile"); .Ve .PP La premie\*`re commande redirige a\*` la fois la sortie standard et la sortie d'erreur dans le fichier temporaire. La seconde commande n'y envoie que la sortie standard d'origine, et la sortie d'erreur d'origine se retrouve envoye\*' vers la sortie standard d'origine. .Sh "Pourquoi \fIopen()\fP ne retourne-t-il pas d'erreur lorsque l'ouverture du tube e\*'choue\ ?" .IX Subsection "Pourquoi open() ne retourne-t-il pas d'erreur lorsque l'ouverture du tube e'choue?" Si le second argument d'un \fIopen()\fR utilisant un tube contient des me\*'tacaracte\*`res du shell, perl fait un \fIfork()\fR puis exe\*'cute un shell pour de\*'coder les me\*'tacaracte\*`res et e\*'ventuellement exe\*'cuter le programme voulu. Si le programme ne peut s'exe\*'cuter, c'est le shell qui rec\*,oit le message et non Perl. Tout ce que verra Perl c'est s'il a re\*'ussi a\*` lancer le shell. Vous pouvez toujours capturer la sortie d'erreur \s-1STDERR\s0 du shell et y chercher les messages d'erreur. Voir "\*(L"Comment capturer la sortie de \s-1STDERR\s0 d'une commande externe\ ?\*(R" ou utiliser IPC::Open3. .PP S'il n'y a pas de me\*'tacaracte\*`res dans l'argument de \fIopen()\fR, Perl exe\*'cute la commande directement, sans utiliser le shell, et peut donc correctement rapporter la bonne exe\*'cution de la commande. .Sh "L'utilisation des apostrophes inverse\*'es dans un contexte vide pose-t-elle proble\*`me\ ?" .IX Subsection "L'utilisation des apostrophes inverse'es dans un contexte vide pose-t-elle proble`me?" A\*` strictement parler, non. Par contre, stylistiquement parlant, ce n'est pas un bon moyen d'e\*'crire du code maintenable. Perl propose plusieurs ope\*'rateurs permettant l'exe\*'cution de commandes externes. Les apostrophes inverse\*'es en sont un : elles capturent la sortie produite par la commande pour que vous l'utilisiez dans votre programme. La fonction \f(CW\*(C`system\*(C'\fR en est un autre : elle ne fait pas cette capture. .PP Conside\*'rons la ligne suivante\ : .PP .Vb 1 \& `cat /etc/termcap`; .Ve .PP On a oublie\*' de ve\*'rifier la valeur de \f(CW$?\fR pour savoir si le programme s'e\*'tait bien de\*'roule\*'. Me\*^me si l'on avait e\*'crit\ : .PP .Vb 1 \& print `cat /etc/termcap`; .Ve .PP ce code pourrait et devrait probablement e\*^tre e\*'crit ainsi\ : .PP .Vb 2 \& system("cat /etc/termcap") == 0 \& or die "cat program failed!"; .Ve .PP Ce qui permet d'avoir la sortie rapidement (au fur et a\*` mesure de sa ge\*'ne\*'ration, au lieu d'avoir a\*` attendre jusqu'a\*` la fin) et ve\*'rifie aussi la valeur de sortie. .PP Avec \fIsystem()\fR vous avez aussi un contro\*^le direct sur une possible interpre\*'tation de me\*'ta\-caracte\*`res, alors que ce n'est pas permis avec des apostrophes inverse\*'es. .Sh "Comment utiliser des apostrophes inverse\*'es sans traitement du shell\ ?" .IX Subsection "Comment utiliser des apostrophes inverse'es sans traitement du shell?" C'est un peu tordu. Vous ne pouvez pas simplement e\*'crire\ : .PP .Vb 1 \& @ok = `grep @opts '$search_string' @filenames`; .Ve .PP Depuis Perl 5.8.0, vous pouvez utiliser \fIopen()\fR avec sa syntaxe a\*` plusieurs arguments. De la me\*^me manie\*`re que pour les appels avec plusieurs arguments des fonctions \fIsystem()\fR et \fIexec()\fR, il n'y a alors plus de passage pas le shell. .PP .Vb 3 \& open( GREP, "\-|", 'grep', @opts, $search_string, @filenames ); \& chomp(@ok = ); \& close GREP; .Ve .PP Vous pouvez aussi faire\ : .PP .Vb 10 \& my @ok = (); \& if (open(GREP, "\-|")) { \& while () { \& chomp; \& push(@ok, $_); \& } \& close GREP; \& } else { \& exec 'grep', @opts, $search_string, @filenames; \& } .Ve .PP De me\*^me qu'avec \fIsystem()\fR, il n'y a aucune intervention du shell lorsqu'on donne une liste d'arguments a\*` \fIexec()\fR. D'autres exemples de ceci se trouvent dans \*(L"Ouvertures Su\*^res d'un Tube\*(R" in perlipc. .PP Notez que si vous utilisez Microsoft, aucune solution a\*` ce proble\*`me vexant n'est possible. Me\*^me si Perl pouvait e\*'muler \fIfork()\fR, vous seriez toujours coince\*'s, parce que Microsoft ne fournit aucune \s-1API\s0 du style argc/argv. .Sh "Pourquoi mon script ne lit-il plus rien de \s-1STDIN\s0 apre\*`s que je lui ai envoye\*' \s-1EOF\s0 (^D sur Unix, ^Z sur \s-1MS\-DOS\s0)\ ?" .IX Subsection "Pourquoi mon script ne lit-il plus rien de STDIN apre`s que je lui ai envoye' EOF (^D sur Unix, ^Z sur MS-DOS)?" Certaines imple\*'mentations de stdio positionnent des indicateurs d'erreur et de fin de fichier qui demandent a\*` e\*^tre annule\*'es d'abord. Le module \s-1POSIX\s0 de\*'finit \fIclearerr()\fR que vous pouvez utiliser. C'est la fac\*,on correcte de traiter ce proble\*`me. Voici d'autres alternatives, moins fiables\ : .IP "1." 4 Gardez sous la main la position dans le fichier, et retournez\-y, ainsi\ : .Sp .Vb 2 \& $where = tell(LOG); \& seek(LOG, $where, 0); .Ve .IP "2." 4 Si cela ne marche pas, essayez de retourner a\*` d'autres parties du fichier, et puis finalement la\*` ou\*` vous le voulez. .IP "3." 4 Si cela ne marche toujours pas, essayez d'aller ailleurs dans le fichier, de lire quelque chose, puis de retourner a\*` l'endroit me\*'morise\*'. .IP "4." 4 Si cela ne marche toujours pas, abandonnez votre librairie stdio et utilisez sysread directement. .Sh "Comment convertir mon script shell en perl\ ?" .IX Subsection "Comment convertir mon script shell en perl?" Apprenez Perl et re\*'e\*'crivez le. Se\*'rieusement, il n'y a pas de convertisseur simple. Des choses complique\*'es en shell sont simples en Perl, et cette complexite\*' me\*^me rendrait l'e\*'criture d'un convertisseur shell\->perl quasi impossible. En re\*'e\*'crivant le programme, vous penserez plus a\*` ce que vous de\*'sirez re\*'ellement faire, et vous vous affranchirez du paradigme de flots de donne\*'es mis bout a\*` bout propre au shell, qui, bien que pratique pour certains proble\*`mes, est a\*` l'origine de nombreuses inefficacite\*'s. .Sh "Puis-je utiliser perl pour lancer une session telnet ou ftp\ ?" .IX Subsection "Puis-je utiliser perl pour lancer une session telnet ou ftp?" Essayez les modules Net::FTP, TCP::Client et Net::Telnet (disponibles sur \s-1CPAN\s0). Pour e\*'muler le protocole telnet, on s'aidera de , mais il est probablement plus facile d'utiliser Net::Telnet directement. .PP Si tout ce que vous voulez faire est pre\*'tendre d'e\*^tre telnet mais n'avez pas du tout besoin de la ne\*'gociation initiale, alors l'approche classique bi-processus suffira\ : .PP .Vb 12 \& use IO::Socket; # nouveau dans 5.004 \& $handle = IO::Socket::INET\->new('www.perl.com:80') \& || die "can't connect to port 80 on www.perl.com: $!"; \& $handle\->autoflush(1); \& if (fork()) { # XXX: undef signifie un e\*'chec \& select($handle); \& print while ; # tout ce qui vient de stdin va vers la prise \& } else { \& print while <$handle>; # tout ce qui vient de la prise va vers stdout \& } \& close $handle; \& exit; .Ve .ie n .Sh "Comment e\*'crire ""expect"" en Perl\ ?" .el .Sh "Comment e\*'crire ``expect'' en Perl\ ?" .IX Subsection "Comment e'crire expect en Perl?" Il e\*'tait une fois une librairie appele\*'e chat2.pl (incluse dans la distribution standard de perl) qui ne fut jamais vraiment termine\*'e. Si vous la trouvez quelque part, \fIne l'utilisez pas\fR. De nos jours, il est plus rentable de regarder du co\*^te\*' du module Expect, disponible sur \s-1CPAN\s0, qui requiert aussi deux autres modules de \s-1CPAN\s0, IO::Pty and IO::Stty. .ie n .Sh "Peut-on cacher les arguments de perl sur la ligne de commande aux programmes comme ""ps""\ ?" .el .Sh "Peut-on cacher les arguments de perl sur la ligne de commande aux programmes comme ``ps''\ ?" .IX Subsection "Peut-on cacher les arguments de perl sur la ligne de commande aux programmes comme ps?" Tout d'abord, notez que si vous faites cela pour des raisons de se\*'curite\*' (afin d'empe\*^cher les autres de voir des mots de passe, par exemple), alors vous feriez mieux de re\*'e\*'crire votre programme de fac\*,on a\*` assurer que les donne\*'es critiques ne sont jamais passe\*'es comme argument. Cacher ces arguments ne rendra jamais votre programme comple\*`tement su\*^r. .PP Pour vraiment alte\*'rer la ligne de commande visible, on peut assigner quelque chose a\*` la variable \f(CW$0\fR, ainsi que documente\*' dans perlvar. Cependant, cela ne marchera pas sur tous les syste\*`mes d'exploitation. Des logiciels de\*'mons comme sendmail y placent leur e\*'tat, comme dans\ : .PP .Vb 1 \& $0 = "orcus [accepting connections]"; .Ve .Sh "J'ai {change\*' de re\*'pertoire, modifie\*' mon environnement} dans un script perl. Pourquoi les changements disparaissent-ils lorsque le script se termine\ ? Comment rendre mes changements visibles\ ?" .IX Subsection "J'ai {change' de re'pertoire, modifie' mon environnement} dans un script perl. Pourquoi les changements disparaissent-ils lorsque le script se termine? Comment rendre mes changements visibles?" .IP "Unix" 4 .IX Item "Unix" A\*` proprement parler, ce n'est pas possible \*(-- le script s'exe\*'cute dans un processus diffe\*'rent du shell qui l'a de\*'marre\*'. Les changements effectue\*'s dans ce processus ne sont pas transmis a\*` son parent \*(-- seulement a\*` ses propres enfants cre\*'es apre\*`s le changement en question. Il y a cependant une astuce du shell qui peut permettre de le simuler en \fIeval()\fRuant la sortie du script dans votre shell\ ; voir la \s-1FAQ\s0 de comp.unix.questions pour plus de de\*'tails. .Sh "Comment fermer le descripteur de fichier attache\*' a\*` un processus sans attendre que ce dernier se termine\ ?" .IX Subsection "Comment fermer le descripteur de fichier attache' a` un processus sans attendre que ce dernier se termine?" En supposant que votre syste\*`me autorise ce genre de chose, il suffit d'envoyer un signal approprie\*' a\*` ce processus (voir \&\*(L"kill\*(R" in perlfunc). Il est d'usage d'envoyer d'abord un signal \s-1TERM\s0, d'attendre un peu, et ensuite seulement d'envoyer le signal \s-1KILL\s0 pour y mettre fin. .Sh "Comment lancer un processus de\*'mon\ ?" .IX Subsection "Comment lancer un processus de'mon?" Si par processus de\*'mon vous entendez un processus qui s'est de\*'tache\*' (dissocie\*' de son terminal de contro\*^le), alors le mode ope\*'ratoire suivant marche en ge\*'ne\*'ral sur la plupart des syste\*`mes Unix. Les utilisateurs de plate-forme non-Unix doivent regarder du co\*^te\*' du module Votre_OS::Process pour des solutions alternatives. .IP "\(bu" 4 Ouvrir /dev/tty et utiliser l'ioctl \s-1TIOCNOTTY\s0 dessus. Voir tty pour les de\*'tails. Ou mieux encore, utiliser la fonction \fIPOSIX::setsid()\fR, pour ne pas avoir a\*` se soucier des groupes de processus. .IP "\(bu" 4 Positionner le re\*'pertoire courant a\*` / .IP "\(bu" 4 Re-ouvrir \s-1STDIN\s0, \s-1STDOUT\s0 et \s-1STDERR\s0 pour qu'ils ne soient plus attache\*'s a\*` leur terminal d'origine. .IP "\(bu" 4 Se placer en arrie\*`re plan ainsi\ : .Sp .Vb 1 \& fork && exit; .Ve .PP Le module Proc::Daemon, disponible sur le \s-1CPAN\s0, fournit une fonction qui re\*'alise ces actions pour vous. .Sh "Comment savoir si je tourne de fac\*,on interactive ou pas\ ?" .IX Subsection "Comment savoir si je tourne de fac,on interactive ou pas?" Bonne question. Parfois \f(CW\*(C`\-t STDIN\*(C'\fR et \f(CW\*(C`\-t STDOUT\*(C'\fR peuvent donner quelque indice, parfois non. .PP .Vb 3 \& if (\-t STDIN && \-t STDOUT) { \& print "Now what? "; \& } .Ve .PP Sur les syste\*`mes \s-1POSIX\s0, on peut tester son groupe de processus pour voir s'il correspond au groupe du terminal de contro\*^le comme suit\ : .PP .Vb 9 \& use POSIX qw/getpgrp tcgetpgrp/; \& open(TTY, "/dev/tty") or die $!; \& $tpgrp = tcgetpgrp(fileno(*TTY)); \& $pgrp = getpgrp(); \& if ($tpgrp == $pgrp) { \& print "foreground\en"; \& } else { \& print "background\en"; \& } .Ve .Sh "Comment sortir d'un blocage sur e\*'ve\*'nement lent\ ?" .IX Subsection "Comment sortir d'un blocage sur e've'nement lent?" Utiliser la fonction \fIalarm()\fR, probablement avec le recours a\*` une capture de signal, comme documente\*' dans \*(L"Signaux\*(R" in perlipc et le chapitre \*(L"Signaux\*(R" du Camel Book. On peut aussi utiliser le module plus flexible Sys::AlarmCall, disponible sur \s-1CPAN\s0. .PP La fonction \fIalarm()\fR n'est pas disponible dans certaines versions de Windows. Pour le savoir, cherchez dans le documentation de votre distribution Perl. .Sh "Comment limiter le temps \s-1CPU\s0\ ?" .IX Subsection "Comment limiter le temps CPU?" Utiliser le module BSD::Resource de \s-1CPAN\s0. .Sh "Comment e\*'viter les processus zombies sur un syste\*`me Unix\ ?" .IX Subsection "Comment e'viter les processus zombies sur un syste`me Unix?" Utiliser le collecteur de \*(L"Signaux\*(R" in perlipc pour appeler \fIwait()\fR lorsque le signal \s-1SIGCHLD\s0 est rec\*,u, ou bien utiliser la technique du double \fIfork()\fR de\*'crite dans \*(L"Comment lancer un processus en arrie\*`re plan\ ?\*(R" in perlfaq8. .Sh "Comment utiliser une base de donne\*'es \s-1SQL\s0\ ?" .IX Subsection "Comment utiliser une base de donne'es SQL?" Le module \s-1DBI\s0 fournit une interface ge\*'ne\*'rique vers la plupart des serveurs ou des syste\*`mes de base de donne\*'es tels que Oracle, \s-1DB2\s0, Sybase, mysql, Postgresql, \s-1ODBC\s0 ou me\*^me des fichiers classiques. Le module \s-1DBI\s0 acce\*`de a\*` ces diffe\*'rents types de base de donne\*'es a\*` travers un pilote spe\*'cifique a\*` chaque base de donne\*'es, ou \s-1DBD\s0 (Data Base Driver). Vous pouvez obtenir la liste comple\*`te des pilotes disponibles sur \s-1CPAN\s0 en consultant . Lisez pour en apprendre plus concernant \s-1DBI\s0. .PP D'autres modules donnent acce\*`s a\*` des bases spe\*'cifiques\ : Win32::ODBC, Alzabo, iodbc et d'autres encore trouvables en cherchant sur \s-1CPAN\s0\ : . .Sh "Comment terminer un appel a\*` \fIsystem()\fP avec un control-C\ ?" .IX Subsection "Comment terminer un appel a` system() avec un control-C?" Ce n'est pas possible. Vous devez imiter l'appel a\*` \fIsystem()\fR vous\-me\*^me (voir perlipc pour un exemple de code) et ensuite fournir votre propre routine de traitement pour le signal \s-1INT\s0 qui passera le signal au sous\-processus. Ou vous pouvez ve\*'rifier si ce signal a e\*'te\*' rec\*,u\ : .PP .Vb 2 \& $rc = system($cmd); \& if ($rc & 127) { die "signal death" } .Ve .Sh "Comment ouvrir un fichier sans bloquer\ ?" .IX Subsection "Comment ouvrir un fichier sans bloquer?" Si vous avez assez de chance pour utiliser un syste\*`me supportant les lectures non bloquantes (ce qui est le cas de la plupart des syste\*`mes Unix), vous devez simplement utiliser les attributs O_NDELAY ou O_NONBLOCK du module Fcntl en les spe\*'cifiant a\*` \fIsysopen()\fR\ : .PP .Vb 3 \& use Fcntl; \& sysopen(FH, "/foo/somefile", O_WRONLY|O_NDELAY|O_CREAT, 0644) \& or die "can't open /foo/somefile: $!"; .Ve .Sh "Comment faire la diffe\*'rence entre les erreurs shell et les erreurs perl\ ?" .IX Subsection "Comment faire la diffe'rence entre les erreurs shell et les erreurs perl?" (contribution de brian d foy, \f(CW\*(C`\*(C'\fR) .PP Lorsque vous lancez un script Perl, il y a quelque chose qui exe\*'cute le script pour vous et ce quelque chose peut e\*'mettre des messages d'erreur. Le script lui\-me\*^me peut e\*'mettre ses propres messages d'avertissement et d'erreur. La plupart du temps, vous ne pouvez pas savoir lequel a e\*'mis quoi. .PP Vous ne pouvez sans doute pas modifier la chose qui exe\*'cute perl, mais vous pouvez modifier la manie\*`re dont perl affiche ses avertissements et ses erreurs en de\*'finissant vos propres fonctions de gestion de ces messages. .PP Conside\*'rons le script suivant, qui contient une erreur pas visiblement e\*'vidente\ : .PP .Vb 1 \& #!/usr/locl/bin/perl \& \& print "Hello World\en"; .Ve .PP Lorsque je tente d'exe\*'cuter ce script depuis mon shell (il se trouve que c'est bash), j'obtiens une erreur. Il semblerait que perl a\*` oublie\*' sa fonction \fIprint()\fR mais en fait c'est ma ligne de shebang (#!...) qui ne contient pas le chemin d'acce\*`s a\*` perl. Donc le shell lance le script et j'obtiens l'erreur\ : .PP .Vb 2 \& $ ./test \& ./test: line 3: print: command not found .Ve .PP Une correction sale et rapide ne\*'cessite un petit peu plus de code mais vous aidera a\*` localiser l'origine du proble\*`me. .PP .Vb 1 \& #!/usr/bin/perl \-w \& \& BEGIN { \& $SIG{_\|_WARN_\|_} = sub{ print STDERR "Perl: ", @_; }; \& $SIG{_\|_DIE_\|_} = sub{ print STDERR "Perl: ", @_; exit 1}; \& } \& \& $a = 1 + undef; \& $x / 0; \& _\|_END_\|_ .Ve .PP Tous les message de perl seront maintenant pre\*'fixe\*'s par \*(L"Perl: \*(R". Le bloc \s-1BEGIN\s0 fonctionne de\*`s la compilation et donc tous les messages d'erreur et d'avertissement du compilateur seront eux aussi pre\*'fixe\*'s par \*(L"Perl: \*(R". .PP .Vb 7 \& Perl: Useless use of division (/) in void context at ./test line 9. \& Perl: Name "main::a" used only once: possible typo at ./test line 8. \& Perl: Name "main::x" used only once: possible typo at ./test line 9. \& Perl: Use of uninitialized value in addition (+) at ./test line 8. \& Perl: Use of uninitialized value in division (/) at ./test line 9. \& Perl: Illegal division by zero at ./test line 9. \& Perl: Illegal division by zero at \-e line 3. .Ve .PP Si vous ne voyez pas \*(L"Perl: \*(R" devant le message, c'est qu'il ne vient pas de perl. .PP Vous pourriez aussi tout simplement connai\*^tre toutes les erreurs de perl mais, bien que ce soit effectivement le cas de certaines personnes, ce n'est certainement pas le vo\*^tre. En revanche, elles sont toutes re\*'pertorie\*'es dans perldiag. Donc si vous n'y trouvez pas cette erreur alors ce que ce n'est probablement pas une erreur perl. .PP Chercher parmi tous les messages d'erreur n'est pas facile alors laissez donc perl le faire pour vous. Utilisez la directive diagnostics qui transforme les messages d'erreurs normaux de perl en un discours un peu plus long sur le sujet. .PP .Vb 1 \& use diagnostics; .Ve .PP Si vous n'obtenez pas un ou deux paragraphes d'explication, il y a de grande chance que ce ne soit pas une erreur perl. .Sh "Comment installer un module du \s-1CPAN\s0\ ?" .IX Subsection "Comment installer un module du CPAN?" La fac\*,on la plus simple est d'utiliser un module lui aussi appele\*' \s-1CPAN\s0 qui le fera pour vous. Ce module est distribue\*' en standard avec les versions de perl 5.004 ou plus. .PP .Vb 1 \& $ perl \-MCPAN \-e shell \& \& cpan shell \-\- CPAN exploration and modules installation (v1.59_54) \& ReadLine support enabled \& \& cpan> install Some::Module .Ve .PP Pour installer manuellement le module \s-1CPAN\s0, ou tout autre module de \&\s-1CPAN\s0 qui se comporte normalement, suivez les e\*'tapes suivantes\ : .IP "1." 4 De\*'sarchiver les sources dans une zone temporaire. .IP "2." 4 .Vb 1 \& perl Makefile.PL .Ve .IP "3." 4 .Vb 1 \& make .Ve .IP "4." 4 .Vb 1 \& make test .Ve .IP "5." 4 .Vb 1 \& make install .Ve .PP Si votre version de perl est compile\*'e sans support pour le chargement dynamique de librairies, alors il vous faudra remplacer l'e\*'tape 3 (\fBmake\fR) par \fBmake perl\fR et vous obtiendrez un nouvel exe\*'cutable \&\fIperl\fR avec votre extension lie\*'e statiquement. .PP Voir ExtUtils::MakeMaker pour plus de de\*'tails sur les extensions de fabrication. Voir aussi la question suivante, \*(L"Quelle est la diffe\*'rence entre require et use\ ?\*(R". .Sh "Quelle est la diffe\*'rence entre require et use\ ?" .IX Subsection "Quelle est la diffe'rence entre require et use?" Perl offre diffe\*'rentes solutions pour inclure du code d'un fichier dans un autre. Voici les diffe\*'rences entre les quelques constructions disponibles pour l'inclusion\ : .PP .Vb 3 \& 1) "do $file" ressemble a\*` "eval `cat $file`", sauf que le premier \& 1.1: cherche dans @INC et met a\*` jour %INC. \& 1.2: entoure le code eval()ue\*' d'une porte\*'e lexicale *inde\*'pendante*. \& \& 2) "require $file" ressemble a\*` "do $file", sauf que le premier \& 2.1: s'arrange pour e\*'viter de charger deux fois un me\*^me fichier. \& 2.2: lance une exception si la recherche, la compilation ou \& l'exe\*'cution de $file e\*'choue. \& \& 3) "require Module" ressemble a\*` "require 'Module.pm'", sauf que le premier \& 3.1: traduit chaque "::" en votre se\*'parateur de re\*'pertoire. \& 3.2: indique au compilateur que Module est une classe, \& passible d'appels indirects. \& \& 4) "use Module" ressemble a\*` "require Module", sauf que le premier \& 4.1: charge le module a\*` la phase de compilation, et non a\*` l'exe\*'cution. \& 4.2: importe ses symboles et se\*'mantiques dans la paquetage courant. .Ve .PP En ge\*'ne\*'ral, on utilise \f(CW\*(C`use\*(C'\fR avec un module Perl ade\*'quat. .Sh "Comment ge\*'rer mon propre re\*'pertoire de modules/bibliothe\*`ques\ ?" .IX Subsection "Comment ge'rer mon propre re'pertoire de modules/bibliothe`ques?" Lorsque vous fabriquez les modules, utilisez les options \s-1PREFIX\s0 et \s-1LIB\s0 a\*` la phase de ge\*'ne\*'ration de Makefiles\ : .PP .Vb 1 \& perl Makefile.PL PREFIX=/mydir/perl LIB=/mydir/perl/lib .Ve .PP puis, ou bien positionnez la variable d'environnement \s-1PERL5LIB\s0 avant de lancer les scripts utilisant ces modules/bibliothe\*`ques (voir perlrun), ou bien utilisez\ : .PP .Vb 1 \& use lib '/mydir/perl/lib'; .Ve .PP C'est presque la me\*^me chose que\ : .PP .Vb 3 \& BEGIN { \& unshift(@INC, '/mydir/perl/lib'); \& } .Ve .PP sauf que le module lib ve\*'rifie les sous\-re\*'pertoires de\*'pendants de la machine. Voir le pragma lib de Perl pour plus d'information. .Sh "Comment ajouter le re\*'pertoire dans lequel se trouve mon programme dans le chemin de recherche des modules / bibliothe\*`ques\ ?" .IX Subsection "Comment ajouter le re'pertoire dans lequel se trouve mon programme dans le chemin de recherche des modules / bibliothe`ques?" .Vb 3 \& use FindBin; \& use lib "$FindBin::Bin"; \& use vos_propres_modules; .Ve .Sh "Comment ajouter un re\*'pertoire dans mon chemin de recherche (@INC) a\*` l'exe\*'cution\ ?" .IX Subsection "Comment ajouter un re'pertoire dans mon chemin de recherche (@INC) a` l'exe'cution?" Voici les moyens sugge\*'re\*'s de modifier votre chemin de recherche\ : .PP .Vb 5 \& la variable d'environnement PERLLIB \& la variable d'environnement PERL5LIB \& l'option perl \-Idir sur la ligne de commande \& le pragma use lib, comme dans \& use lib "$ENV{HOME}/ma_propre_biblio_perl"; .Ve .PP Ce dernier est particulie\*`rement utile, parce qu'il prend en compte les fichiers propres a\*` une architecture donne\*'e. Le module pragmatique lib.pm a e\*'te\*' introduit dans la version 5.002 de Perl. .Sh "Qu'est\-ce que socket.ph et ou\*` l'obtenir\ ?" .IX Subsection "Qu'est-ce que socket.ph et ou` l'obtenir?" C'est un fichier a\*` la mode de perl4 de\*'finissant des contantes pour la couche re\*'seau du syste\*`me. Il est parfois construit en utilisant h2ph lorsque Perl est installe\*', mais d'autres fois il ne l'est pas. Les programmes modernes utilisent \f(CW\*(C`use Socket;\*(C'\fR a\*` la place. .SH "AUTEURS" .IX Header "AUTEURS" Copyright (c) 1997\-1999 Tom Christiansen, Nathan Torkington et d'autres auteurs sus\-cite\*'s. Tous droits re\*'serve\*'s. .PP Cette documentation est libre ; vous pouvez la redistribuer et/ou la modifier sous les me\*^mes conditions que Perl lui\-me\*^Me. .PP Inde\*'pendemment de sa distribution, tous les exemples de code de ce fichier sont ici place\*'s dans le domaine public. Vous e\*^tes autorise\*'s et encourage\*'s a\*` utiliser ce code dans vos programmes que ce soit pour votre plaisir ou pour un profit. Un simple commentaire dans le code en pre\*'cisant l'origine serait de bonne courtoisie mais n'est pas obligatoire. .SH "TRADUCTION" .IX Header "TRADUCTION" .Sh "Version" .IX Subsection "Version" Cette traduction franc\*,aise correspond a\*` la version anglaise distribue\*'e avec perl 5.8.8. Pour en savoir plus concernant ces traductions, consultez . .Sh "Traducteur" .IX Subsection "Traducteur" Traduction initiale : Raphae\*:l Manfredi . Mise a\*` jour : Roland Trique , Paul Gaborit (paul.gaborit at enstimac.fr). .Sh "Relecture" .IX Subsection "Relecture" Simon Washbrook, Ge\*'rard Delafond.