2013-07-19 2 views
1

J'écris un wrapper à une commande externe ("sox", si cela peut aider) avec Perl "Tk". J'ai besoin de l'exécuter de manière asynchrone, bien sûr, pour éviter de bloquer le MainLoop de tk(). Mais, j'ai besoin de lire sa sortie pour informer l'utilisateur de la progression de la commande.Perl (tk): comment exécuter de manière asynchrone une commande système, en étant capable de réagir à sa sortie?

Je teste une solution comme celle-ci, en utilisant IPC :: Open3:

{ 
    $| = 1; 
    $pid = open3(gensym, ">&STDERR", \*FH, $cmd) or error("Errore running command \"$cmd\""); 
} 
while (defined($ch = FH->getc)) { 
    notifyUser($ch) if ($ch =~ /$re/); 
} 
waitpid $pid, 0; 
$retval = $? >> 8; 
POSIX::close($_) for 3 .. 1024; # close all open handles (arbitrary upper bound) 

Mais bien sûr, les blocs de boucle while MainLoop jusqu'à cmd $ ne termine.

Existe-t-il un moyen de lire la poignée de sortie de manière asynchrone? Ou devrais-je utiliser des fourches standard? La solution devrait également fonctionner sous win32.

Répondre

3

Pour une lecture non bloquante d'un handle de fichier, jetez un oeil à Tk::fileevent.

Voici un exemple de script comment on peut utiliser un tuyau, un processus fourchue et FileEvent ensemble:

use strict; 
use IO::Pipe; 
use Tk; 

my $pipe = IO::Pipe->new; 
if (!fork) { # Child XXX check for failed forks missing 
    $pipe->writer; 
    $pipe->autoflush(1); 
    for (1..10) { 
     print $pipe "something $_\n"; 
     select undef, undef, undef, 0.2; 
    } 
    exit; 
} 
$pipe->reader; 

my $mw = tkinit; 
my $text; 
$mw->Label(-textvariable => \$text)->pack; 
$mw->Button(-text => "Button", -command => sub { warn "Still working!" })->pack; 
$mw->fileevent($pipe, 'readable', sub { 
        if ($pipe->eof) { 
         warn "EOF reached, closing pipe..."; 
         $mw->fileevent($pipe, 'readable', ''); 
         return; 
        } 
        warn "pipe is readable...\n"; 
        chomp(my $line = <$pipe>); 
        $text = $line; 
       }); 
MainLoop; 

bifurquent peuvent ou peuvent ne pas fonctionner sous Windows. En outre, il faut être prudent en forçant dans Tk; vous devez vous assurer que seulement un des deux processus fait X11/GUI, sinon de mauvaises choses arriveront (erreurs X11, plantages ...). Une bonne approche consiste à fourcher avant de créer la Tk MainWindow.

+1

Tk :: IO semble emballer cette fonctionnalité dans un joli paquet; la documentation pour cela implique beaucoup de casse, mais j'ai utilisé une version piratée avec Expect pour contrôler les processus pendant un moment (wow, depuis 2005!). Y at-il quelque chose à ce sujet qui le rend impropre à l'utilisation? –

+0

J'ai tendance à oublier 'Tk :: IO' - si cela fonctionne pour vous, alors c'est bien! En fait, il utilise '' fileevent' en interne, aussi, le tube est créé en utilisant 'open '- |" ', et la commande système est exécutée avec' exec', donc vous n'avez pas à vous inquiéter des erreurs X11 ici. –

+0

Super! Je ne connaissais pas Tk :: fileevent ... Je pourrais forcer mon travail de code laid en insérant un appel "$ mw-> update" dans la boucle while, mais c'est définitivement une solution plus propre, que je vais tester dès que possible – MarcoS

Questions connexes