2012-03-09 24 views
7

Estoy tratando de leer datos sin buffer de una tubería en Perl. Por ejemplo en el siguiente programa:Leer datos sin búfer de la tubería en Perl

open FILE,"-|","iostat -dx 10 5"; 
$old=select FILE; 
$|=1; 
select $old; 
$|=1; 

foreach $i (<FILE>) { 
    print "GOT: $i\n"; 
} 

iostat escupe datos cada 10 segundos (cinco veces). Es de esperar que este programa haga lo mismo. Sin embargo, en su lugar, parece colgar durante 50 segundos (es decir, 10x5), después de lo cual escupe todos los datos.

¿Cómo puedo obtener la devolución de los datos que estén disponibles (sin amortiguar), sin esperar todo el camino para EOF?

P.S. He visto numerosas referencias a esto en Windows, estoy haciendo esto bajo Linux.

+4

Debería utilizar 'while' not a' foreach'. Y su almacenamiento en búfer de salida no es importante, dado que es un identificador de entrada, no un identificador de salida. – tchrist

+0

¿Cuál es la diferencia cuando se usa while y foreach? – Jean

+0

@alertjean: en 'foreach my $ i () {...}', la lectura del archivo se realiza en contexto de lista, es decir, se lee el archivo completo antes de que las líneas se procesen en el bucle 'foreach'. En 'while (mi $ i = ) {...}', la lectura se realiza en contexto escalar, es decir, cada línea se lee y luego se procesa en el bloque while, antes de leer la siguiente línea. –

Respuesta

5
#!/usr/bin/env perl 

use strict; 
use warnings; 



open(PIPE, "iostat -dx 10 1 |")  || die "couldn't start pipe: $!"; 

while (my $line = <PIPE>) { 
    print "Got line number $. from pipe: $line"; 
} 

close(PIPE)       || die "couldn't close pipe: $! $?"; 
+1

Esto funciona sin habilitar siquiera autoflush STDOUT – Jean

+0

Este ejemplo pertenece a perldoc readline. –

1

Si está bien esperar en su script Perl en lugar del comando linux, esto debería funcionar. No creo que Linux le devuelva el control al script de Perl antes de que se complete la ejecución del comando.

#!/usr/bin/perl -w 
my $j=0; 
while($j!=5) 
{ 
    open FILE,"-|","iostat -dx 10 1"; 
    $old=select FILE; 
    $|=1; 
    select $old; 
    $|=1; 

    foreach $i (<FILE>) 
    { 
     print "GOT: $i"; 
    } 
    $j++; 
    sleep(5); 
} 
+6

** El ajuste '$ |' solo afecta el almacenamiento en búfer de salida. ** No puede afectar el almacenamiento en búfer de salida del otro programa de esa manera. Además, ¿qué pasa con el extraño abrir en lugar de simplemente 'abrir (PIPEHANDLE," iostat -dx 10 1 | ") || morir "no se puede iniciar la tubería"; Nunca recuerdo '" | - "' vs '" - | "' a mí mismo. De todos modos, si el programa 'iostat' no está vaciando sus búferes en una tubería, debe recurrir a ptys, que es una verdadera molestia pero inevitable. – tchrist

1

tengo a continuación el código de trabajo para mí

#!/usr/bin/perl 
use strict; 
use warnings; 
open FILE,"-|","iostat -dx 10 5"; 

while (my $old=<FILE>) 
{ 
    print "GOT: $old\n"; 
} 
+0

¿Por qué no 'abrir (ARCHIVO," iostat -dx 10 5 | ")'? – tchrist

+0

@tchist porque 'abre PIPE, '- |', 'iostat', '-dx', 10, 5' o die $! – larelogio

1

Las soluciones hasta ahora no funcionó para mí en lo que respecta a retirar del búfer (Windows ActiveState Perl 5.10).

De acuerdo con http://perldoc.perl.org/PerlIO.html, "Para obtener una secuencia sin búfer, especifique una capa sin búfer (por ejemplo, unix) en la llamada abierta:".

Así

open(PIPE, '-|:unix', 'iostat -dx 10 1') or die "couldn't start pipe: $!"; 

while (my $line = <PIPE>) { 
    print "Got $line"; 
} 

close(PIPE); 

que trabajó en mi caso.

Cuestiones relacionadas