¿Por qué se detiene un ciclo while después de ser suspendido?

10

¿Por qué es que al usar bash y suspender un ciclo while, el ciclo se detiene después de reanudarse? Breve ejemplo a continuación.

$ while true; do echo .; sleep 1; done
.
.
^Z
[1]+  Stopped                 sleep 1
$ fg
sleep 1
$

Estoy familiarizado con las señales, y supongo que este puede ser el comportamiento natural de bash aquí, pero me gustaría entender mejor por qué se comporta de esta manera en particular.

bkzland
fuente
porque tiene que manejar una interrupción y tiene que reflejarlo con precisión $?al regresar, y entonces trueno es así true. probablemente. Yo creo que.
mikeserv
1
Espero que este comentario no se marque, pero responderé a su pregunta con otra pregunta, al estilo Unix koan: "¿Por qué un estudiante deja de pelear en el patio de recreo después de ser suspendido?" La respuesta es, porque ya no está en el patio de recreo donde tiene la capacidad de comenzar peleas. Por lo tanto, el comportamiento en cuestión simplemente se ha detenido.
rubynorails
Detiene el comando, el bucle está roto. Luego, reanuda el comando individual sleep 1, no el bucle.
123
1
Relevante
123

Respuestas:

10

Esto parece un error en varios shells, funciona como se esperaba con ksh93 y zsh .

Antecedentes:

La mayoría de los shells parecen ejecutar el ciclo while dentro del shell principal y

Bourne Shell suspende todo el shell si escribe ^ Z con un shell sin inicio de sesión

bash suspende solo el sleepy luego deja el bucle while a favor de imprimir un nuevo indicador de shell

el guión hace que este comando no se pueda suspender

Con ksh93 , las cosas funcionan de manera muy diferente:

ksh93 hace lo mismo, mientras que el comando se inicia la primera vez, pero como sleepes un buitin en ksh93, ksh93 tiene un controlador que hace que el bucle while se bifurque en el shell principal y luego se suspenda en el momento en que escribe ^ Z.

Si en ksh93 escribe más tarde fg, el hijo bifurcado que aún ejecuta el bucle continúa.

Verá la principal diferencia al comparar los mensajes de control de trabajo de bash y ksh93:

informes de bash :

[1]+ Stopped sleep 1

pero ksh93 informa:

^Z[1] + Stopped while true; do echo .; sleep 1; done

zsh se comporta de manera similar a ksh93

Con ambos shells, tiene un solo proceso (el shell principal) siempre que no escriba ^ Z, y dos procesos de shell después de escribir ^ Z.

astuto
fuente
¿no termina dashrealmente manejando la señal cuando termina el bucle? en el [d]?ashcódigo fuente hay todas estas macros para INTON e INTOFF dispersas, y típicamente las señales recibidas en estado INTOFF realmente se manejan en (o alrededor) INTON . de todos modos, solo tengo curiosidad porque creo que lo sabes mejor, es una gran respuesta. gracias.
mikeserv
Raramente uso dash y recientemente lo busqué y lo compilé para comparaciones de rendimiento con bash, ksh93 y mi Bourne Shell. Al hacer estas pruebas, descubrí que el guión parece ser principalmente rápido porque no incluye soporte para caracteres de varios bytes. Se sleep 100puede suspender y reanudar una sola dash, por lo que parece que dashconoce los problemas de este comando y deshabilita selectivamente el control del trabajo.
schily
entonces, en sus pruebas, ¿fue capaz de igualar dashel rendimiento en otros shells al dejar caer el procesamiento multibyte? y sí, dashadmite el control del trabajo, pero el estándar dice que un shell interactivo debe ignorar TSTP, y ejecutar un ciclo while en el shell actual en un terminal interactivo no es menos un shell interactivo que cualquier otro.
mikeserv
No probé esto exactamente, pero pude ver que aunque el tablero consume más tiempo de CPU del sistema que ksh93 o Bourne Shell (principalmente porque emite más llamadas fork), usa menos tiempo de CPU del usuario y esto da como resultado un total similar Tiempo de CPU en comparación con mi versión de Bourne Shell. Al tratar de reducir el tiempo de CPU del usuario en Bourne Shell, sé que la mayor parte de este tiempo se gasta en conversiones multibyte.
schily
4

Escribí a uno de los coautores de Bash sobre el tema, y ​​aquí está su respuesta:

No es realmente un error, pero sin duda es una advertencia.

La idea aquí es suspender procesos, que son una unidad de granularidad diferente a los comandos de shell. Cuando se suspende un proceso, vuelve al shell (con un estado distinto de cero, lo que tiene consecuencias cuando, por ejemplo, detiene un proceso que es la prueba de bucle), que tiene una opción: puede salir del bucle o continuarlo. , dejando atrás el proceso detenido. Bash elige, y siempre ha elegido, salir de los bucles cuando se detiene un trabajo. Continuar el ciclo rara vez es lo que quieres.

Algunos otros shells hacen cosas como bifurcar una copia del shell cuando un proceso se suspende debido a SIGTSTP y detener ese proceso. Bash nunca ha hecho eso, parece más complicado de lo que garantiza el beneficio, pero si alguien quiere enviar ese código como un parche, echaré un vistazo para incorporar los cambios.

Entonces, si alguien quiere enviar un parche, use las direcciones de correo electrónico que se encuentran en las páginas del manual.

Outrin
fuente