<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>