(Inspirado por la respuesta de Gilles)
Con el ISIGindicador establecido, la única forma de que el Childscript se obtenga SIGINTsin que su padre lo obtenga SIGINTes que esté en su propio grupo de procesos. Esto se puede lograr con la set -mopción.
Si activa la -mopción en el Childscript de shell, realizará el control del trabajo sin ser interactivo. Esto hará que ejecute cosas en un grupo de proceso separado, evitando que el padre reciba el SIGINTcuando INTRse lee el personaje.
Aquí está la descripción POSIX de la -mopción :
-mEsta opción se admitirá si la implementación admite la opción Utilidades de portabilidad del usuario. Todos los trabajos se ejecutarán en sus propios grupos de procesos. Inmediatamente antes de que el shell emita un aviso después de completar el trabajo en segundo plano, se escribirá un mensaje de error que informe el estado de salida del trabajo en segundo plano. Si se detiene un trabajo en primer plano, el shell escribirá un mensaje de error estándar a ese efecto, formateado como se describe en la utilidad de trabajos. Además, si un trabajo cambia de estado además de salir (por ejemplo, si se detiene para entrada o salida o es detenido por una señal SIGSTOP), el shell debe escribir un mensaje similar inmediatamente antes de escribir el siguiente mensaje. Esta opción está habilitada de forma predeterminada para shells interactivos.
La -mopción es similar a -i, pero no altera el comportamiento del shell tanto como lo -ihace.
Ejemplo:
el Parentguión:
#!/bin/sh
trap 'echo "PARENT: caught SIGINT; exiting"; exit 1' INT
echo "PARENT: pid=$$"
echo "PARENT: Spawning child..."
./Child
echo "PARENT: child returned"
echo "PARENT: exiting normally"
el Childguión:
#!/bin/sh -m
# ^^
# notice the -m option above!
trap 'echo "CHILD: caught SIGINT; exiting"; exit 1' INT
echo "CHILD: pid=$$"
echo "CHILD: hit enter to exit"
read foo
echo "CHILD: exiting normally"
Esto es lo que sucede cuando presiona Control+ Cmientras Childespera la entrada:
$ ./Parent
PARENT: pid=12233
PARENT: Spawning child...
CHILD: pid=12234
CHILD: hit enter to exit
^CCHILD: caught SIGINT; exiting
PARENT: child returned
PARENT: exiting normally
Observe cómo el controlador del padre SIGINTnunca se ejecuta.
Alternativamente, si prefiere modificar en Parentlugar de Child, puede hacer esto:
el Parentguión:
#!/bin/sh
trap 'echo "PARENT: caught SIGINT; exiting"; exit 1' INT
echo "PARENT: pid=$$"
echo "PARENT: Spawning child..."
sh -m ./Child # or 'sh -m -c ./Child' if Child isn't a shell script
echo "PARENT: child returned"
echo "PARENT: exiting normally"
el Childscript (normal; no es necesario -m):
#!/bin/sh
trap 'echo "CHILD: caught SIGINT; exiting"; exit 1' INT
echo "CHILD: pid=$$"
echo "CHILD: hit enter to exit"
read foo
echo "CHILD: exiting normally"
Ideas alternativas
- Modifique los otros procesos en el grupo de procesos en primer plano para ignorarlos
SIGINTdurante la duración de Child. Esto no responde a su pregunta, pero puede obtener lo que desea.
- Modificar
Childa:
- Use
stty -gpara hacer una copia de seguridad de la configuración actual del terminal.
- Correr
stty -isigpara no generar señales con las INTR, QUITy SUSPcaracteres.
- En el fondo, leer la entrada del terminal y enviar las señales a sí mismo como apropiado (por ejemplo, correr
kill -QUIT 0cuando Control+ \se lee, kill -INT $$cuando Control+ Cse lee). Esto no es trivial, y puede que no sea posible hacer que funcione sin problemas si el Childscript o cualquier cosa que ejecute esté destinado a ser interactivo.
- Restaure la configuración del terminal antes de salir (idealmente desde una trampa activada
EXIT).
- Igual que el # 2, excepto que en lugar de ejecutarse
stty -isig, espere a que el usuario presione Entero alguna otra tecla no especial antes de matar Child.
Escriba su propia setpgidutilidad en C, Python, Perl, etc. que pueda usar para llamar setpgid(). Aquí hay una implementación cruda de C:
#define _XOPEN_SOURCE 700
#include <unistd.h>
#include <signal.h>
int
main(int argc, char *argv[])
{
// todo: add error checking
void (*backup)(int);
setpgid(0, 0);
backup = signal(SIGTTOU, SIG_IGN);
tcsetpgrp(0, getpid());
signal(SIGTTOU, backup);
execvp(argv[1], argv + 1);
return 1;
}
Ejemplo de uso de Child:
#!/bin/sh
[ "${DID_SETPGID}" = true ] || {
# restart self after calling setpgid(0, 0)
exec env DID_SETPGID=true setpgid "$0" "$@"
# exec failed if control reached this point
exit 1
}
unset DID_SETPGID
# do stuff here
ksh). Ejemplos:${ENV}es de origen, el shell no se cerrará inmediatamente cuando encuentre un errorSIGQUITySIGTERMse ignorará.Bueno, de la pregunta de desbordamiento de pila a la que hizo referencia, establece claramente que el padre debe estar configurado para manejar la señal.
En segundo lugar, la referencia POSIX establece claramente que "si se establece ISIG, el carácter INTR se descartará cuando se procese".
Eso son dos opciones. El tercero sería ejecutar al niño en su propio grupo de procesos.
fuente