¿Quieres mejorar esta pregunta? Agrega detalles y aclara el problema editando esta publicación.
Cerrado hace 3 años.
Mejorar esta pregunta
Para entender
Si Bash está esperando que se complete un comando y recibe una señal para
que se ha establecido una trampa, la trampa no se ejecutará hasta que se complete el comando
.
Cuando Bash está esperando un comando asíncrono a través de la espera incorporada ,
la recepción de una señal para la que se ha establecido una trampa hará que la
espera interna vuelva inmediatamente con un estado de salida superior a
128, inmediatamente después de lo cual se ejecuta la trampa.
del manual de Bash,
ejecuto lo siguiente:
-
En mis dos ejemplos, SIGINT (enviado con Ctrl-C) termina un trabajo en primer plano
(el primer caso en la cita) y un trabajo en segundo plano
(el segundo caso en la cita) ambos inmediatamente, sin esperar para
que lo completen.¿Significa la primera oración de la cita que si Bash está ejecutando un
trabajo en primer plano y recibe la señalSIGINT
, la trampa de la señalSIGINT
, cuando se establece, se ejecutará hasta que se complete el comando?
En caso afirmativo, por qué en mi primer ejemplo,ctrl-C
hacer que el trabajo en primer plano
exista inmediatamente antes de que pueda completarse?$ sleep 10000 # a foreground job ^C $ sleep 10000 & # a background job [1] 21219 $ wait 21219 ^C $ echo $? 130
-
¿Qué significa “una señal para la que se ha tendido una trampa” decir,
-
una señal
arg
cuya trampa se ha especificado a través detrap arg sigspec
, o -
una señal que no se ignora, o
-
¿una señal cuya trampa no es la predeterminada?
En los ejemplos de mi parte 1, no configuré una trampa para SIGINT, por lo que la señal tiene su
controlador predeterminado (que sale de cualquier ciclo de ejecución). Es una
señal que tiene su controlador predeterminado considerado tener una trampa que se ha
tendido? -
-
Puse una trampa para
SIGINT
, peroctrl-C
hará que el siguiente comando
salga antes de completarse. Entonces, ¿es contrario a la primera
oración de mi cita?$ trap "echo You hit control-C!" INT $ bash -c 'sleep 10; echo "$?"' ^C $
Antes de tenderle la trampa a
SIGINT
,ctrl-C
también hará que el mismo comando
salga antes de completarse. Entonces, ¿es contrario a la primera
oración de mi cita?$ bash -c 'sleep 10; echo "$?"' ^C
-
¿Podría dar algunos ejemplos para explicar qué significan las dos oraciones en
la cita?
Gracias.
Respuesta aceptada:
¿Qué significa "una señal para la que se ha tendido una trampa"?
Esa es una señal para la que se ha definido un controlador (con trap 'handling code' SIG
) donde el código de manejo no está vacío, ya que eso haría que se ignorara la señal.
Por lo tanto, las señales que tienen su disposición predeterminada no son señales para las que se ha establecido una trampa.
Parte de esa cita en su publicación también se aplica a las señales que tienen su disposición predeterminada, aunque obviamente no es la parte sobre ejecutar el trampa , ya que no se han definido trampas para ellos.
El manual habla sobre la entrega de señales al shell , no a los comandos que ejecuta desde ese shell.
1.
Si Bash está esperando que se complete un comando y recibe una señal para la que se ha establecido una trampa, la trampa no se ejecutará hasta que se complete el comando.
(1)
por qué en mi primer ejemplo, ctrl-C hace que el trabajo en primer plano salga inmediatamente antes de que pueda completarse
Si ejecuta sleep 10
en el indicador de un shell interactivo , el shell pondrá ese trabajo en primer plano (a través de un ioctl()
en el dispositivo tty que le dice a la disciplina de la línea terminal qué grupo de procesos es el de primer plano), por lo que solo sleep
obtendrá un SIGINT en ^C
y el caparazón interactivo no , por lo que no es útil probar ese comportamiento.
-
El shell principal, ya que es interactivo, no recibirá el SIGINT ya que su proceso no está en el grupo de procesos de primer plano.
-
Cada comando es libre de manejar las señales como les plazca.
sleep
no hace nada especialmente con SIGINT, por lo que obtendrá la disposición predeterminada (terminar) a menos que se haya ignorado SIGINT al inicio.
(2) Si ejecuta sleep 10
en un shell no interactivo ,
bash -c 'sleep 10; echo "$?"'
Tanto el bash
no interactivo shell y sleep
recibirá el SIGINT cuando presione Ctrl-C.
Si bash
salió de inmediato, podría dejar el sleep
comando que se ejecuta desatendido en segundo plano si ignora o maneja la señal SIGINT. Entonces, en cambio,
bash
como la mayoría de las otras conchas, bloques la recepción de señales (al menos algunas señales) cuando se esperan órdenes.- La entrega se reanuda después de que finaliza el comando (sobre lo cual se ejecutan las trampas). Eso también evita que los comandos en trampas se ejecuten simultáneamente con otros comandos.
En ese ejemplo anterior, sleep
morirá con SIGINT, así que bash
no tiene que esperar mucho para manejar su propio SIGINT (aquí para morir ya que no agregué una trap
en SIGINT).
(3) cuando presiona Ctrl+C mientras ejecuta el shell no interactivo:
bash -c 'sh -c "trap "" INT; sleep 3"; echo "$?"'
(sin trap
en SIGINT) bash
no es asesinado por el SIGINT. bash
, como algunos otros shells, tratan SIGINT y SIGQUIT de manera especial. Implementan la espera y salida cooperativa comportamiento descrito en https://www.cons.org/cracauer/sigint.html (y se sabe que causa algunas molestias como los scripts que llaman a SIGINT que maneja comandos que no se pueden interrumpir con ^C
)
(4) Para probar correctamente, debe ejecutar un bash
no interactivo que tiene una trampa SIGINT configurada y llama a un comando que no muere de inmediato en SIGINT como:
bash -c 'trap "echo Ouch" INT; sh -c "trap "" INT; sleep 3"'
bash
está esperando a sh
que tiene (junto con sleep
) SIGINT ignorado (debido a la trap "" INT
), por lo que SIGINT no eliminará sleep
ni sh
. bash
no ignora SIGINT, pero su manejo se difiere hasta sh
devoluciones. Ves Ouch
siendo mostrado, no sobre Ctrl+C , pero después de sleep
y sh
han terminado normalmente.
Tenga en cuenta que la trap
El comando establece una trampa para una señal para el mismo shell en el que se ejecuta. Así que cuando la trap
el comando se ejecuta fuera del shell no interactivo y en el shell principal,
$ trap "echo You hit control-C!" INT $ bash -c 'sleep 10; echo "$?"' ^C $
el bash
no interactivo y sleep
los comandos no heredarán esa trap
del caparazón principal. Los controladores de señales se pierden al ejecutar un comando diferente (execve()
borra todo el espacio de direcciones del proceso, incluido el código del controlador). Al execve()
, las señales que tenían un controlador definido vuelven a la disposición predeterminada, las que se ignoraron permanecen ignoradas.
Además de eso, en la mayoría de los shells, trap
s también se restablecen en subcapas.
2.
Cuando Bash está esperando un comando asíncrono a través de la espera incorporada , la recepción de una señal para la que se ha configurado una trampa hará que la espera interna vuelva inmediatamente con un estado de salida superior a 128, inmediatamente después de lo cual se ejecuta la trampa.
Al usar wait
explícitamente , wait
es interrumpido por cualquier señal que tenga una trampa configurada (y obviamente también aquellas que matan el caparazón por completo).
Eso hace que sea difícil obtener el estado de salida de un comando de manera confiable cuando hay señales atrapadas :
$ bash -c 'trap "echo Ouch" INT; sh -c "trap "" INT; sleep 10" & wait "$!"; echo "$?"'
^COuch
130
En ese caso, sleep
y sh
no fueron asesinados por SIGINT (ya que lo ignoran). Todavía wait
regresa con un 130
estado de salida porque se recibió una señal (SIGINT) mientras esperaba sh
. Tendrías que repetir el wait "$!"
hasta sh
realmente termina para obtener sh
estado de salida.