<div dir="ltr"><div dir="ltr"><div>Bonjour Philippe,</div><div><br></div>L&#39;opérateur qx capture ce qui est envoyé par la commande sur la sortie standard.</div><div dir="ltr"><br></div><div>Voyons donc ce qui est envoyé sur la sortie standard. Pour cela il suffit de comparer les deux commandes suivantes depuis un shell :</div><div>  Â  read -n 1 -p &quot;un message &quot; l</div><div>  Â  read -n 1 -p &quot;un message &quot; l &gt;/dev/null</div><div>La première commande laisse passer ce qui est envoyé sur la sortie standard pour l&#39;envoyer vers le terminal, tandis que la seconde l&#39;envoie Ã  la poubelle.</div><div>Résultat : les affichages sur le terminal sont identiques. Pourquoi ? Parce que la commande n&#39;écrit rien sur la sortie standard. Le caractère tapé (qui est affiché) n&#39;est d&#39;ailleurs pas envoyé par la commande. C&#39;est juste le comportement normal du terminal où les caractères tapés sont répliqués Ã  l&#39;affichage (Notez qu&#39;il existe un moyen de désactiver ce comportement, par exemple pour la saisie de mot de passe).</div><div>Donc forcément, qx ne capture rien.</div><div><br></div><div>Je t&#39;invite Ã  relire le manuel de la commande &quot;read&quot;. C&#39;est d&#39;ailleurs une commande spéciale : c&#39;est un &quot;shell builtin&quot;, c&#39;est Ã  dire une commande interne. C&#39;est donc dans la documentation de ton shell que tu trouveras ces informations : &quot;man bash&quot;, puis chercher dans la section &quot;SHELL BUILTIN COMMANDS&quot;. En ligne et en français ici : <a href="https://man.cx/bash(1)/fr#heading31">https://man.cx/bash(1)/fr#heading31</a></div><div><br></div><div>Que fait cette commande &quot;read&quot; : elle lit des caractères sur l&#39;entrée standard (connectée par défaut au terminal) et stocke le résultat dans une variable d&#39;environnement, en l&#39;occurence &quot;l&quot; puisque c&#39;est le nom donné sur la ligne de commande. Comme c&#39;est une commande interne, la valeur lue reste dans l&#39;environnement privé du shell. Il faut trouver un moyen de la communiquer Ã  l&#39;extérieur. Il suffit pour cela de demander l&#39;affichage du contenu de cette variable. Avec la commande &quot;printf&quot; (pour qu&#39;il n&#39;y ait pas de \n ajouté comme avec &quot;echo&quot;).</div><div><br></div><div>  Â  { read -n 1 -p &quot;un message &quot; l ; printf %s $l; }</div><div><div>  Â  { read -n 1 -p &quot;un message &quot; l ; printf %s $l; } &gt; /dev/null</div><div></div></div><div><br></div><div>Cette fois il y a bien une différence entre les deux commandes : la première affiche bien le résultat.</div><div>Note: les accolades autour des deux commandes permettent de les grouper afin de gérer la redirection pour les deux commandes (read, printf) ensembles.</div><div><br></div><div>Il est donc maintenant possible d&#39;utiliser qx (notez qu&#39;il faut Ã©chapper les % et les $) :</div><div>  Â  $c=qx{read -n 1 -p &quot;un message &quot; l;  printf \%s \$l};</div><div><br></div><div>Exemple :</div><div>  Â  perl -E &#39;$c=qx{read -n 1 -p &quot;un message &quot; l; printf \%s \$l}; say &quot;\nCaractère lu: [$c]&quot;&#39;</div><div><br></div><div>J&#39;ai Ã©crit tout ceci pour expliquer ce qui se passe. Mais ce n&#39;est absolument pas la bonne façon d&#39;écrire du Perl. Voici pourquoi. La raison principale est que le script Perl lance un shell qui va exécuter deux commandes.</div><div>- ces deux commandes sont des commandes internes du shell. Donc le programme perl dépend du shell utilisé dans l&#39;environnement où le script est exécuté. Si le shell de l&#39;utilisateur est fish au lieu de bash, ou si le script est exécuté sous Windows, le script ne marchera plus.</div><div>- le fait de lancer un shell (c.à.d. un nouveau processus) pour faire l&#39;opération est un gaspillage des ressources de l&#39;ordinateur.</div><div><br></div><div>If faut donc plutôt chercher une solution en pur Perl qui sera Ã  la fois plus portable et plus efficace.</div><div>La fonction sysread (perldoc -f sysread) permet directement de lire des octets.</div><div>Essayons :</div><div><div>  Â  perl -E &#39;print &quot;un message &quot;; sysread(STDIN, $c, 1); say &quot;\nCaractère lu: [$c]&quot;&#39;</div></div><div>Est-ce que Ã§a marche ? Non. Deux problèmes :</div><div>1. le message &quot;un message &quot; n&#39;est pas affiché avant la saisie. Problème avec STDOUT.</div><div>2. le programme lit bien un caractère, mais il est bloqué tant que l&#39;on ne tape pas Entrée. Problème avec STIN.</div><div><br></div><div>Ces deux problèmes sont liés aux mécanismes d&#39;échange des programmes avec le terminal : le buffering. C&#39;est un mécanisme qui date d&#39;une Ã©poque où l&#39;on voulait réduire optimiser les communications avec le terminal et pour cela réduire les Ã©changes en envoyant et recevant des lignes complètes plutôt que caractère par caractère. Donc en sortie le contenu n&#39;est envoyé au terminal que lorsqu&#39;on envoye un saut de ligne, et en entrée le terminal n&#39;envoie ce qui a Ã©té tapé que lorsque la touche Entrée est appuyée. Nous avons donc besoin de désactiver ces deux mécanismes pour que notre programme fonctionne correctement.</div><div>Pour l&#39;entrée, il faut activer l&quot;autoflush&quot; (voir perldoc IO::Handle). <a href="https://metacpan.org/pod/IO::Handle">https://metacpan.org/pod/IO::Handle</a></div><div>Pour la sortie, on peut utiliser Term::ReadKey qui permet de contrôler le terminal. <a href="https://metacpan.org/pod/Term::ReadKey">https://metacpan.org/pod/Term::ReadKey</a> </div><div>  Â ReadMode &#39;cbreak&#39;; # pour désactiver le buffering</div><div>  Â ReadMode &#39;normal&#39;; # pour le réactiver</div><div><br></div><div><br></div><div><div><div>  Â  perl -MTerm::ReadKey -E &#39;STDOUT-&gt;autoflush(1); print &quot;un message &quot;; ReadMode &#39;cbreak&#39;; sysread(STDIN, $c, 1); ReadMode &#39;normal&#39;; say &quot;\nCaractère lu: [$c]&quot;&#39;</div></div><div></div></div><div><br></div><div>Mais tout ceci est géré par le module IO::Prompt, alors autant l&#39;utiliser.</div><div><a href="https://metacpan.org/pod/IO::Prompt">https://metacpan.org/pod/IO::Prompt</a><br></div><div><br></div><div>Olivier.</div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">Le jeu. 5 nov. 2020 Ã Â 07:19, Philippe Delavalade &lt;<a href="mailto:philippe.delavalade@orange.fr">philippe.delavalade@orange.fr</a>&gt; a Ã©crit :<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Bonjour la liste.<br>
<br>
Avec bash, on peut récupérer un caractère frappé au clavier sans qu&#39;il soit<br>
suivi de &lt;entrée&gt;.<br>
<br>
Avec &#39;read -n 1 l&#39;., le caractère frappé est dans la variable &#39;l&#39;.<br>
<br>
Dans un script perl j&#39;essaie de faire la même chose avec la ligne<br>
$c=qx{read -n 1 -p &quot;un message &quot; l}<br>
mais $c ne contient pas le caractère frappé au clavier. l&#39;aide de perldoc<br>
sur qx ne m&#39;a pas permis d&#39;avancer.<br>
<br>
Je passe sûrement Ã  côté d&#39;un truc simple mais...<br>
<br>
Merci par avance de votre aide.<br>
<br>
-- <br>
Philippe<br>
_______________________________________________<br>
Perl mailing list<br>
<a href="mailto:Perl@mongueurs.net" target="_blank">Perl@mongueurs.net</a><br>
<a href="http://listes.mongueurs.net/mailman/listinfo/perl" rel="noreferrer" target="_blank">http://listes.mongueurs.net/mailman/listinfo/perl</a><br>
Attention, les archives sont publiques<br>
</blockquote></div></div>