IPC::Run
facilita la ejecución de procesos hijo
con los que se puede interaccionar utilizando ficheros, pipes y
seudoterminales (denominadas también
pseudo-ttys 6.1 ó pty ).
Veamos un ejemplo sencillo:
lhp@nereida:~/Lperl/src/ipcrun$ cat -n ipccat 1 #!/usr/bin/perl -w 2 use strict ; 3 4 my @cat = qw( cat ) ; 5 my ( $in_q, $out_q, $err_q ) ; 6 7 use IPC::Run qw( start pump finish timeout ) ; 8 9 # Incrementally read from / write to scalars. Note that $in_q 10 # is a queue that is drained as it is used. $h is for "harness". 11 my $h = start \@cat, \$in_q, \$out_q, \$err_q, timeout( 10 ); 12 13 $in_q .= "some input\n" ; 14 pump $h until $out_q =~ /input\n/g ; 15 print "---\n$out_q" ; 16 17 $in_q .= "some more input\n" ; 18 pump $h until $out_q =~ /\G.*more input\n/ ; 19 print "---\n$out_q" ; 20 21 $in_q .= "some final input\n" ; 22 pump $h until $out_q =~ /.*final input\n/ ; 23 print "---\n$out_q" ; 24 25 $in_q .= "some extra input\n" ; 26 finish $h or die "cat returned $?" ; 27 28 warn $err_q if $err_q ; 29 print "---\nFinally:\n$out_q" ;Los procesos hijos son reunidos en un harness, arrancados (línea 11) y ejecutados hasta su finalización o hasta que sean abortados (por ejemplo, con un
die
).
Existen dos modos de trabajo. Uno utiliza run()
el cual funciona
como una extensión de system()
. El otro, al que corresponde
el ejemplo anterior viene dado por la tripleta start,
pump , finish .
La función start
se encarga de crear el harness y lanzar los subprocesos
vía fork
o exec
y arranca los cronómetros
(véase perldoc(
IPC::Run::Timers )
.
El primer argumento de start
es el comando y sus argumentos.
Por eso es un array.
La función pump
nos permite muestrear la actividad de los mismos.
La función finish
(línea 26)
permite monitorizar la actividad del harness
hasta su terminación.
Como se muestra en las líneas 14, 18 y 22 la lectura con pump utiliza expresiones regulares para detectar los puntos de parada. Se puede usar una sintáxis de función, como en el ejemplo, o la de flecha como método:
$h->pump
Si la expresión regular no casa se produce un atasco.
Los Timeouts lanzan excepciones que hacen que pump
retorne después de pasado un cierto tiempo.
El método finish debe ser llamado después del
último pump
. En caso contrario se acumularan los
procesos defunct
y podemos tener pérdidas de
descriptores de ficheros. El método finish
retorna TRUE
si y sólo si todos los hijos retornan 0 y su terminación no fué la consecuencia de
una señal (véase sección
3.4) y no se produjo un coredump ,
esto es la variable $?
está undef
(véase sección
1.6).
La ejecución del código anterior produce la siguiente salida:
lhp@nereida:~/Lperl/src/ipcrun$ ipccat --- some input --- some input some more input --- some input some more input some final input --- Finally: some input some more input some final input some extra input
Veamos un segundo ejemplo, en el que se establece una sesión
con un proceso que ejecuta la calculadora bc de Unix.
La sesión calcula el factorial de un número enviando sucesivas
entradas a bc
y obteniendo sus resultados:
lhp@nereida:~/Lperl/src/ipcrun$ cat -n fact.pl 1 #!/usr/bin/perl -w 2 use strict ; 3 use IPC::Run qw( start timeout ) ; 4 5 die "usage: $0 <num>\n\nwhere <num> is a positive integer\n" unless @ARGV ; 6 my $i = shift ; 7 die "\$i must be > 1, not '$i'" unless $i =~ /^\d+$/ && $i > 1 ; 8 9 my ( $in, $out ) ; 10 11 my $h = start ['bc'], \$in, \$out, timeout( 5 ) ; 12 13 $in = "fact = i = $i ; i\n" ; 14 15 while () { 16 $out = '' ; 17 $h->pump until $out =~ s/.*?([-+]?\d+)\n/$1/g ; 18 print "bc said: $out\n" ; 19 if ( $out <= 0 ) { 20 print "result = ",-$out,"\n" ; 21 $in = undef ; 22 last ; 23 } 24 elsif ( $out eq '2' ) { 25 ## End of calculation loop, get bc to output the result 26 $in = "-fact\n" ; 27 } 28 else { 29 $in = "i = i - 1 ; fact = fact * i ; i\n" ; 30 } 31 } 32 33 $h->finish ;Para detectar el final hacemos que la calculadora devuelva el resultado cambiado de signo (línea 26). Al ejecutar obtenemos la salida:
lhp@nereida:~/Lperl/src/ipcrun$ ./fact.pl 6 bc said: 6 bc said: 5 bc said: 4 bc said: 3 bc said: 2 bc said: -720 result = 720
Casiano Rodríguez León