2012-02-09 16 views
6

Estamos tratando de averiguar cómo ejecutar una aplicación java desde un script de Perl, pero aún así poder leer periódicamente desde el STDOUT de la aplicación java.¿Cómo veo un STDOUT de un programa en ejecución de un programa perl que lo llamó?

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"; 

queríamos ser capaz de leer desde el gestor de archivo, $ fh_dmcrcv, cada pocos minutos o tal vez mediante la creación de un AnyEvent io gatillo cuando hay actividad en el gestor de archivo.

Sin embargo, cuando intento leer desde el gestor de archivo, se bloquea si uso algo como esto:

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

Hemos intentado varios enfoques, no creo que podamos utilizar Archivo :: cola, ya que parece que el módulo necesita un archivo real. El problema parece ser que $ fh_dcmrcv nos bloquea cuando leemos, no estamos seguros del enfoque correcto sobre cómo lograr lo que queremos.

editar # salida 1

Cuando ejecutamos nuestro script Perl que estamos viendo como esto:

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 

El guión, process_files.pl está emitiendo los mens .:

running dcmrcv.bat 
dcmrcv.bat started 

Los mensajes. desde el programa Java son: Iniciar servidor escucha en el puerto 11112 11: 55: 13.495 INFO - empezar a escuchar en 0.0.0.0/0.0.0.0:11112

En este caso estamos haciendo eco de aquellos que por el simple hecho de esta pregunta, realmente queremos analizar periódicamente ciertos mensajes. y nunca hacer eco de ninguno de ellos.

Cualquier idea es apreciado,

-Sam

+1

¿Puedes escribir la salida de la aplicación en un archivo (temporal) y luego usar 'File :: Tail'? – mob

+0

Estamos tratando de evitar ese enfoque. No queremos tener que administrar este archivo en términos de tener que rotarlo o recortarlo. – slm

+1

¿Ha intentado usar fctrl para establecer el descriptor en O_NONBLOCK? – frankc

Respuesta

4

La mayoría de los sistemas admiten una función de 0 argumentos select (también empaquetada muy bien en IO::Select) que le puede indicar si hay entrada esperando en sockethandle o pipehandle.En Windows, select es compatible únicamente con tomas de corriente, lo que conduce a esta solución bizantino:

  1. Crear un par de sockets
  2. Tenedor y ejecutar el comando en un proceso hijo
  3. en el proceso hijo, recuperar la salida de comandos y escribir a la toma de
  4. en el padre, utilizar y seleccione las operaciones de lectura en el zócalo según se desee

Ejemplo:

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); 
    } 
} 

¿Está seguro de que no quiere simplemente escribir su salida de comando en un archivo temporal?

+0

Este 90% funcionó. Necesitaba agregar un 'B-> flush' justo después de' print B' para que el búfer del zócalo limpiara toda la salida que estaba pendiente. – slm

+0

Me duele aceptar esto ya que es un truco total tener que usar tunnel IO a través del módulo Socket, pero no he podido encontrar ningún otro enfoque que funcione además de esto. Entonces, felicidades, esta es la mejor respuesta que pude encontrar. – slm

+1

Gracias @sim. La portabilidad es una perra – mob

0

tratar de leer con este lugar:

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

respecto

+0

Se han intentado variaciones de este y el mismo resultado. La lectura desde Filehandle bloquea el progreso de Perl. – slm

+1

tienes razón. Probablemente desee comprobar si su sistema admite abrir un archivo con la opción de no bloqueo, por lo que leer no se bloqueará si no hay nada que leer desde el descriptor del archivo. Puede encontrar algunos consejos en sysopen – quicoju

2

Uso IO::Select o cuatro argumento select() de leer cuando la lectura no lo hará bloquear. EDITAR: No importa, usted es on Windows, por lo que esto no funcionará. Una opción: haga que se lea un proceso intermedio de este conducto y mantenga un archivo intermediario rellenado con la longitud de cola que necesite. Bleh.

Dicho esto, la mejor manera de leer "cada pocos minutos" de una tubería es leer cada pocos segundos.

+1

* de perl leídos cada pocos segundos * - esto es especialmente cierto si su comando produce una gran cantidad de salida. El tamaño predeterminado del búfer en las tuberías y los zócalos puede ser bastante pequeño, y el comando se bloqueará cuando no haya más espacio para escribir en la tubería. – mob

Cuestiones relacionadas