[Cascavel-pm] IPC::Open3 comes to the rescue! (Was: Re: Print Loading ao executar system)

Daniel Ruoso daniel em ruoso.com
Quinta Dezembro 11 03:40:07 PST 2008


Em Ter, 2008-12-09 às 03:35 -0800, Patty Silva escreveu:
> Pessoal, 
> Tem como eu imprimir na tela "Loading ................." quando
> executa o system??

Olá,

Pessoal, eu tenho me mantido meio calado ultimamente, mas vendo esse
thread enorme sem ninguem dar a solução para um problema que, precisamos
reconhecer, não é "de iniciante", resolvi dar a solução...

A resposta curta é: "Não use system".

A resposta longa é:


#!/usr/bin/perl
use strict;
use warnings;

use Symbol;
# essa linha define símbolos para os três filehandles,
# acho que eu vi isso pela primeira vez no PBP
my ($wtr, $rdr, $err) = map { gensym } 1..3;

use IPC::Open3;
my $pid = open3($wtr, $rdr, $err,
                'ls', '-la');

# considerando que o comando não recebe nada pelo stdin
close $wtr;

# usar o IO::Handle é legal porque ele dá uma visão OO sobre
# os filehandles, o que facilita algumas coisas...
use IO::Handle;
# por exemplo:
$_->blocking(0) for ($rdr, $err);
STDOUT->autoflush(1);

# usar o IO::Select também é legal, porque te permite acompanhar
# filehandles de uma maneira mais esperta
use IO::Select;
my $sel = IO::Select->new($rdr, $err);

# vamos fazer um loop, e ver se o comando escreveu alguma coisa,
# se ele não escrever em 1 segundo, imprimimos um "."
while (1) {
  my @ready = $sel->can_read(1000);
  foreach my $io (@ready) {
    my $type = $io == $rdr ? '[STDOUT]' : '[STDERR]';

    # Como estamos fazendo leitura não bloqueante, não devemos
    # usar <$io>...
    if (read $io, my $buf, 1024) {
      print $type, ' ', $buf, $/;
    } else {
      # se read retornar 0 ou undef, é porque acabou o arquivo ou tem
      # algum erro no filehandle, então vamos tirar do select.
      $sel->remove($io);
    }
  }

  # imprime o pontinho...
  print '.' unless @ready;

  # sai se não tem mais nenhum filehandle
  last unless scalar $sel->handles;
};


# espera o processo sair de verdade;
waitpid $pid, 0;

__END__


e é isso aí...



Mais detalhes sobre a lista de discussão Cascavel-pm