2012-02-09 36 views
6

Chúng tôi đang cố gắng tìm ra cách để chạy một ứng dụng java từ bên trong một kịch bản perl nhưng vẫn có thể đọc định kỳ từ STDOUT của ứng dụng java.Làm cách nào để xem STDOUT của chương trình đang chạy từ chương trình perl được gọi là chương trình này?

print "running dcmrcv.bat\n"; 

open my $fh_dcmrcv, "-|", 'z:\apps\dcm4che\dcm4che-2.0.26\bin\dcmrcv.bat \ 
    DCMRCV:11112 -dest z:\dcmrcv -journal z:\dcmrcv', 
    or die "could not execute dcmrcv: $!"; 

print "dcmrcv.bat started\n"; 

Chúng tôi muốn để có thể đọc từ filehandle, $ fh_dmcrcv, cứ mỗi vài phút hoặc có thể bằng cách thiết lập một AnyEvent io kích hoạt khi có hoạt động trên filehandle.

Tuy nhiên, khi tôi cố gắng và đọc từ filehandle, nó ngăn chặn nếu tôi sử dụng một cái gì đó như thế này:

foreach my $line (<$fh_dmcrcv>) { 
    print $line; 
} 

Chúng tôi đã thử một số phương pháp tiếp cận, không nghĩ rằng chúng ta có thể sử dụng File :: Tail, vì có vẻ như mô-đun đó cần một tệp thực sự. Vấn đề có vẻ là $ fh_dcmrcv đang chặn chúng tôi khi chúng tôi đọc từ đó, không thực sự chắc chắn về cách tiếp cận chính xác về cách đạt được những gì chúng tôi muốn.

EDIT # 1

Khi chúng tôi chạy script perl, chúng ta đang nhìn thấy đầu ra như thế này:

Z:\projects\demo_2>process_files.pl 
running dcmrcv.bat 
dcmrcv.bat started 
Start Server listening on port 11112 
11:55:13,495 INFO - Start listening on 0.0.0.0/0.0.0.0:11112 

Các kịch bản, process_files.pl được phát ra những thông điệp .:

running dcmrcv.bat 
dcmrcv.bat started 

Thông điệp. từ chương trình java là: Bắt đầu máy chủ nghe trên cổng 11112 11: 55: 13,495 THÔNG TIN - Bắt đầu nghe trên 0.0.0.0/0.0.0.0:11112

Trong trường hợp này, chúng tôi đang lặp lại những điều đó chỉ vì mục đích của câu hỏi này, thực sự chúng tôi muốn phân tích định kỳ cho một số thông điệp nhất định. và không bao giờ lặp lại bất kỳ thứ gì trong số chúng.

Bất kỳ cái nhìn sâu sắc được đánh giá cao,

-Sam

+1

Bạn có thể ghi đầu ra của ứng dụng vào một tệp (tạm thời) và sau đó sử dụng 'Tệp :: đuôi'? – mob

+0

Chúng tôi đang cố tránh phương pháp đó. Chúng tôi không muốn phải quản lý tệp này về việc phải xoay hoặc cắt tệp. – slm

+1

Bạn đã thử sử dụng fctrl để đặt bộ mô tả thành O_NONBLOCK? – frankc

Trả lời

4

Hầu hết các hệ thống đều hỗ trợ chức năng 423 đối số select (cũng được đóng gói độc đáo trong IO::Select) có thể cho bạn biết liệu có đầu vào đang chờ trên sockethandle hoặc pipehandle hay không.Trong Windows, select chỉ được hỗ trợ trên các socket, dẫn đến giải pháp Byzantine này:

  1. Tạo một cặp socket
  2. Fork và chạy các lệnh trong một quá trình con
  3. Trong quá trình trẻ em, lấy ra lệnh và ghi nó vào ổ cắm
  4. Trong phụ huynh, sử dụng lựa chọn và đọc hoạt động trên các ổ cắm như mong muốn

Ví dụ:

use Socket; 
use IO::Select; 
use Time::HiRes; 
$cmd = $^X . ' -MMath::BigInt -e "$_=1; ' 
     . 'print qq/$_!=/,Math::BigInt->new($_)->bfac(),qq/\n\n\n/' 
     . ' for 4000..4100"'; 
socketpair A,B,AF_UNIX,SOCK_STREAM,PF_UNSPEC; # step 1 
if (fork() == 0) { 
    open my $fh, '-|', $cmd;     # step 2 
    while (<$fh>) { 
     print B;        # step 3 
    } 
    close $fh; 
    exit $? >> 8; 
} 
$s = IO::Select->new(); 
$s->add(\*A); 
for (;;) { 
    if ($s->can_read(0.25)) {     # step 4 
     $line = <A>; 
     print "Do something with command output: $line"; 
    } else { 
     print "No output now. Could be doing something else ...\n"; 
     Time::HiRes::sleep(0.25); 
    } 
} 

Bạn có chắc chắn không muốn chỉ viết đầu ra lệnh của mình vào tệp tạm thời không?

+0

90% này hoạt động. Tôi cần thêm một 'B-> flush' ngay sau 'print B' để lấy bộ đệm của socket để xóa tất cả đầu ra đang chờ xử lý. – slm

+0

Tôi đau lòng chấp nhận điều này vì nó là một hack toàn bộ trong việc phải sử dụng đường hầm IO thông qua mô-đun Socket nhưng tôi đã không thể tìm ra cách tiếp cận nào khác hoạt động bên cạnh điều này. Vì vậy, congrats, đây là câu trả lời tốt nhất mà tôi có thể tìm thấy. – slm

+1

Cảm ơn @sim. Portability là một bitch. – mob

0

Cố gắng đọc với thay này:

while (my $line = <$fh_dmcrcv>) { 
    print $line; 
} 

liên quan

+0

Đã thử các biến thể của kết quả này và cùng một kết quả. Đọc từ filehandle khối prol perl. – slm

+1

bạn nói đúng. Có lẽ bạn có thể muốn kiểm tra xem hệ thống của bạn có hỗ trợ mở tệp bằng tùy chọn không chặn không, do đó, đọc sẽ không bị khóa nếu không có gì để đọc từ bộ mô tả tệp. Bạn có thể tìm thấy một số gợi ý trong perl's sysopen – quicoju

2

Sử dụng IO::Select hoặc bốn đối số select() để đọc khi đọc sẽ không khối. EDIT: Nevermind, bạn đang on Windows, vì vậy thao tác này sẽ không hoạt động. Một lựa chọn: có một quy trình trung gian đọc từ đường ống này và giữ một tệp trung gian chứa đầy bất kỳ chiều dài đuôi nào bạn cần. Bleh.

Điều đó nói rằng, cách tốt nhất để đọc "vài phút một lần" từ một đường ống là để đọc từ nó sau mỗi vài giây.

+1

* đọc từ nó sau mỗi vài giây * - điều này đặc biệt đúng nếu lệnh của bạn tạo ra nhiều đầu ra. Kích thước bộ đệm mặc định trên đường ống và ổ cắm có thể khá nhỏ và lệnh sẽ chặn khi không còn chỗ để viết trên đường ống. – mob

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