We're trying to figure out how to run a java application from within a perl script but still be able to periodically read from the java app's STDOUT.
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";
We wanted to be able to read from the filehandle, $fh_dmcrcv, every few minutes or perhaps by setting up an AnyEvent io trigger when there is activity on the filehandle.
However, when I try and read from the filehandle, it blocks if I use something like this:
foreach my $line (<$fh_dmcrcv>) {
print $line;
}
We've tried several approaches, don't think we can use File::Tail, since it seems that module needs an actual file. The issue seems to be that $fh_dcmrcv is blocking us when we read from it, not really sure of the correct approach on how to achieve what we want.
EDIT #1
When we run our perl script we're seeing output like this:
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
The script, process_files.pl is emitting the msgs.:
running dcmrcv.bat
dcmrcv.bat started
The msgs. from the java program are: Start Server listening on port 11112 11:55:13,495 INFO - Start listening on 0.0.0.0/0.0.0.0:11112
In this case we're echoing those out just for the sake of this question, really we want to periodically parse for certain msgs. and never echo any of them out.
Any insight is appreciated,
-Sam
Most systems support a 4-argument select
function (also packaged nicely in IO::Select
) that can tell you whether there is input waiting on sockethandle or pipehandle. In Windows, select
is only supported on sockets, which leads to this byzantine solution:
Example:
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);
}
}
Are you sure you don't want to just write your command output to a temp file?
Use IO::Select or four-argument select()
to read when reading will not block. EDIT: Nevermind, you're on Windows, so this won't work. One option: have an intermediary process read from this pipe and keep an intermediary file filled with just whatever tail-length you need of it. Bleh.
That said, the best way to read "every few minutes" from a pipe is to read from it every few seconds.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With