GNU/Linux >> Tutoriales Linux >  >> Linux

Al escribir Ctrl-c en una terminal, ¿por qué el trabajo en primer plano no finaliza hasta que se completa?

Cerrado . Esta pregunta necesita detalles o claridad. Actualmente no está aceptando respuestas.

¿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:

  1. 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ñal SIGINT , la trampa de la señal
    SIGINT , 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
    
  2. ¿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 de trap 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?

  3. Puse una trampa para SIGINT , pero ctrl-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
    
  4. ¿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.

Relacionado:Linux:¿aumentar el volumen de un video MKV desde la terminal de Linux?

(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).

Relacionado:¿Cómo formatear una partición en un sistema de archivos rápidamente?

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.


Linux
  1. Al usar Vlc, ¿por qué el protector de pantalla sigue activándose?

  2. ¿Por qué el servicio persistente de Iptables no guarda los cambios?

  3. ¿Por qué el Wget no murió después de la pérdida de la conexión Ssh?

  4. ¿Por qué salta el cursor al escribir?

  5. llamar a una función cuando el programa haya terminado con ctrl c

Por qué todavía me encanta Alpine para el correo electrónico en la terminal de Linux

Bash-insulter:un script que insulta al usuario cuando escribe un comando incorrecto

¿Cuál es la forma correcta de hacer que mi aplicación PyQt se cierre cuando se elimina desde la consola (Ctrl-C)?

¿Cuándo se maneja una señal y por qué alguna información se congela?

¿Por qué no sale un ciclo bash while cuando se conecta a un subcomando terminado?

¿Por qué no puedo desplazarme en la terminal?