2012-03-09 23 views
7

Tôi đang cố gắng đọc dữ liệu không được lọc từ một đường ống trong Perl. Ví dụ: trong chương trình bên dưới:Đọc dữ liệu chưa được lọc từ đường ống trong Perl

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

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

iostat phun ra dữ liệu sau mỗi 10 giây (năm lần). Bạn mong đợi chương trình này sẽ làm như vậy. Tuy nhiên, thay vào đó nó xuất hiện để treo trong 50 giây (tức là 10x5), sau đó nó phun ra tất cả dữ liệu.

Làm thế nào tôi có thể nhận được trả lại bất kỳ dữ liệu nào có sẵn (theo cách thức không bị cản trở), mà không phải đợi tất cả các cách cho EOF?

P.S. Tôi đã thấy nhiều tài liệu tham khảo này dưới Windows - Tôi đang làm điều này dưới Linux.

+4

Bạn nên sử dụng 'while' không phải là' foreach'. Và bộ đệm đầu ra của bạn là không quan trọng, cho rằng đó là một đầu vào xử lý không phải là một xử lý đầu ra. – tchrist

+0

Sự khác biệt khi sử dụng trong khi và foreach là gì? – Jean

+0

@alertjean: Trong 'foreach my $ i () {...}', đọc tệp được thực hiện trong ngữ cảnh danh sách, nghĩa là toàn bộ tệp được đọc trước khi các dòng được xử lý trong vòng lặp 'foreach'. Trong 'while (my $ i = ) {...}', việc đọc được thực hiện trong ngữ cảnh vô hướng, nghĩa là mỗi dòng được đọc và sau đó được xử lý trong khối trong khi trước khi đọc dòng kế tiếp. –

Trả lời

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

Tính năng này hoạt động mà không cần bật tự động STDOUT – Jean

+0

Ví dụ này thuộc về readline perldoc. –

1

Nếu bạn có thể đợi trong kịch bản Perl của mình thay vì lệnh linux, thao tác này sẽ hoạt động. Tôi không nghĩ rằng Linux sẽ cung cấp cho kiểm soát trở lại kịch bản Perl trước khi thực hiện lệnh được hoàn thành.

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

** Đặt '$ |' chỉ ảnh hưởng đến bộ đệm đầu ra. ** Bạn không thể ảnh hưởng đến bộ đệm đầu ra của chương trình khác theo cách đó. Cộng với những gì có mở lạ thay vì chỉ 'mở (PIPEHANDLE," iostat -dx 10 1 | ") || chết "không thể bắt đầu đường ống"; '? Tôi không bao giờ có thể nhớ "" | - "' vs '" - | "' bản thân mình. Dù sao, nếu chương trình 'iostat' không xóa bộ đệm của nó trên một đường ống, bạn phải chuyển sang ptys, điều này thực sự gây phiền toái nhưng không thể tránh khỏi. – tchrist

1

Tôi có mã dưới đây làm việc cho tôi

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

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

Tại sao không mở (FILE, "iostat -dx 10 5 |") '? – tchrist

+0

@tchist vì 'mở PIPE, '- |', 'iostat', '-dx', 10, 5' hoặc chết $! – larelogio

1

Các giải pháp cho đến nay đã không làm việc cho tôi liên quan đến unbuffering (Windows ActiveState Perl 5.10).

Theo http://perldoc.perl.org/PerlIO.html, "Để nhận luồng không được lọc, hãy chỉ định một lớp không bị chặn (ví dụ: unix) trong cuộc gọi mở:".

Vì vậy

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

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

close(PIPE); 

mà làm việc trong trường hợp của tôi.

Các vấn đề liên quan