2010-07-14 13 views
7

¿Qué está pasando aquí? Pensé que SIGINT sería enviado al grupo de proceso en primer plano.¿Por qué no se atrapa a SIGINT aquí?

(creo que, tal vez, que el sistema() se ejecuta una concha que está creando un nuevo grupo de procesos para el proceso hijo? ¿Alguien puede confirmar esto?)

% perl 
local $SIG{INT} = sub { print "caught signal\n"; }; 
system('sleep', '10'); 

luego presione Ctrl + D luego Ctrl + c inmediatamente y observe que la "señal capturada" nunca se imprime.

Siento que esto es una cosa simple ... de todos modos para evitar esto? El problema es que al ejecutar un montón de comandos a través del sistema, se mantiene presionada ctrl + c hasta que se completen todas las iteraciones (porque perl nunca obtiene el SIGINT) y es bastante molesto ...

¿Cómo se puede solucionar esto? (Ya probada usando tenedor() directamente y entiendo que esto funciona ... esto no es una solución aceptable en este momento)

ACTUALIZACIÓN: Atención, esto no tiene nada que ver con "dormir", solo el hecho de que el comando toma una cantidad arbitraria de tiempo para ejecutarse, que es considerablemente mayor que la perl a su alrededor. Tanto que presionar ctrl + c se envía al comando (como está en el grupo de proceso en primer plano?) Y de alguna manera logra nunca ser enviado a perl.

Respuesta

4

de perldoc system:

Desde SIGINT y SIGQUIT se ignoran durante la ejecución del sistema, si espera que su programa para terminar en la recepción de estas señales que tendrá que hacer arreglos para hacerlo por sí mismo sobre la base de la valor de retorno

@args = ("command", "arg1", "arg2"); 
system(@args) == 0 
    or die "system @args failed: $?" 

Si desea inspeccionar manualmente el fracaso del sistema, se puede comprobar todos modos de fallo posibles por la inspección de $? de esta manera:

if ($? == -1) { 
    print "failed to execute: $!\n"; 
} 
elsif ($? & 127) { 
    printf "child died with signal %d, %s coredump\n", 
     ($? & 127), ($? & 128) ? 'with' : 'without'; 
} 
else { 
    printf "child exited with value %d\n", $? >> 8; 
} 

Alternativamente, usted puede inspeccionar el valor de $ {^ CHILD_ERROR_NATIVE} con la W *() llama desde el módulo de POSIX

+3

Creo que necesito leer la documentación una vez más: -/Gracias. – dlamotte

+1

Agregaría que la razón por la que necesita inspeccionar el valor de retorno del niño es que su caparazón entrega el^c/INT a todo el grupo de proceso, a Perl y a los niños, en este caso terminando a su hijo 'sleep 10'. Si simplemente 'mides -INT $ perl_pid' desde otro intérprete de comandos, perl estará feliz de indicarte SIG_IGN. – pilcrow

0

yo no lo entiendo muy bien lo que estamos tratando de lograr aquí ... pero has necesitado simplemente comparando a:

perl -wle'local $SIG{INT} = sub { print "caught signal"; }; sleep 10;' 

Puede explicar el efecto que usted está tratando de ir a dar, y ¿Por qué estás invocando el caparazón? ¿Puedes simplemente llamar al programa externo directamente sin involucrar al caparazón?

+0

por favor mi sección Update, "dormir" no tiene nada para hacer con eso ... es simplemente un marcador de posición para algún proceso arbitrario. Podría cambiarse fácilmente con "grep something", que se colgará para siempre, ya que espera leer datos de stdin – dlamotte

+0

@xyld: me doy cuenta de que el sueño es un marcador de posición. Estaba preguntándote por qué necesitabas invocar el shell, en lugar de simplemente llamar a tu proceso directamente. – Ether

+0

No estoy explícitamente, pero el intérprete de Perl puede hacerlo como parte de "system()". – dlamotte

Cuestiones relacionadas