2012-03-09 3 views
7

Я пытаюсь прочитать данные unbufferd из трубы в Perl. Например, в программе ниже:Чтение небуферизованных данных из трубы в Perl

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

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

iostat выплескивает данные каждые 10 секунд (пять раз). Вы ожидали бы, что эта программа будет делать то же самое. Однако вместо этого он, кажется, виснет в течение 50 секунд (т. Е. 10x5), после чего он выплескивает все данные.

Как я могу получить, чтобы вернуть все доступные данные (небуферизованным образом), не дожидаясь завершения EOF?

P.S. Я видел многочисленные ссылки на это под Windows - я делаю это под Linux.

+4

Вы должны использовать 'while' не' foreach'. И ваша буферизация вывода несущественна, учитывая, что это ручка ввода, а не выходной дескриптор. – tchrist

+0

В чем разница при использовании while и foreach? – Jean

+0

@alertjean: В 'foreach my $ i () {...}' чтение файла выполняется в контексте списка, то есть весь файл считывается до того, как строки обрабатываются в цикле 'foreach'. В 'while (my $ i = ) {...}' чтение выполняется в скалярном контексте, то есть каждая строка считывается, а затем обрабатывается в блоке while до того, как будет прочитана следующая строка. –

ответ

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

Это работает даже без включения STDOUT autoflush – Jean

+0

Этот пример относится к perldoc readline. –

1

Если в командной строке Perl вместо команды linux стоит подождать, это должно сработать. Я не думаю, что Linux вернет управление скрипту Perl до завершения выполнения команды.

#!/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

** Установка '$ |' влияет только на буферизацию вывода. ** Вы не можете повлиять на буферизацию вывода другой программы. Плюс, что со странным открытым, а не просто открытым (PIPEHANDLE, «iostat -dx 10 1 |») || die "can not start pipe"; '? Я никогда не помню '' | - '' vs '" - | "' себя. Во всяком случае, если программа 'iostat' не смывает свои буферы по трубе, вам нужно обратиться к ptys, что является реальной проблемой, но не подлежит ремонту. – tchrist

1

У меня есть ниже код работает для меня

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

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

Почему бы не 'open (FILE," iostat -dx 10 5 | ")'? – tchrist

+0

@tchist, потому что 'open PIPE, '- |', 'iostat', '-dx', 10, 5' или die $! – larelogio

1

Решения до сих пор не работает для меня относительно unbuffering (Windows ActiveState Perl 5.10).

Согласно http://perldoc.perl.org/PerlIO.html, «Чтобы получить небуферизованный поток, укажите открытый буфер (например: unix) в открытом вызове:".

Так

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

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

close(PIPE); 

, который работал в моем случае.

Смежные вопросы