¿Alguien puede explicar en detalle lo que hace "set -m"?

16

En la página del manual , solo dice:

-m El control de trabajos está habilitado.

Pero, ¿qué significa esto realmente?

Encontré este comando en una pregunta SO , tengo el mismo problema que OP, que es "la tela no puede iniciar Tomcat". Y set -mresuelto esto. El OP explicó un poco, pero no entiendo del todo:

El problema estaba en las tareas en segundo plano, ya que se eliminarán cuando finalice el comando.

La solución es simple: simplemente agregue "set -m;" prefijo antes del comando.

laike9m
fuente

Respuestas:

10

Citando la documentación de bash (de man bash):

JOB CONTROL
       Job  control  refers to  the  ability  to selectively  stop
       (suspend) the execution of  processes and continue (resume)
       their execution at a later point.  A user typically employs
       this facility via an interactive interface supplied jointly
       by the operating system kernel's terminal driver and bash.

Entonces, dicho simplemente, tener set -m(el valor predeterminado para shells interactivos) le permite a uno usar elementos integrados como fgy bg, que se deshabilitarían en set +m(el valor predeterminado para shells no interactivos).

Sin embargo, no es obvio para mí cuál es la conexión entre el control del trabajo y la eliminación de los procesos en segundo plano al salir, pero puedo confirmar que hay uno: la ejecución set -m; (sleep 10 ; touch control-on) &creará el archivo si uno abandona el shell justo después de escribir ese comando, pero set +m; (sleep 10 ; touch control-off) &no lo hará.

Creo que la respuesta se encuentra en el resto de la documentación para set -m:

-m      Monitor  mode. [...]                     Background pro‐
        cesses run in a separate process group and a  line  con‐
        taining  their exit status is printed upon their comple‐
        tion.

Esto significa que los trabajos en segundo plano iniciados set +mno son "procesos en segundo plano" reales (los "procesos en segundo plano son aquellos cuya ID de grupo de procesos difiere de la terminal"): comparten la misma ID de grupo de procesos que el shell que los inició, en lugar de tener sus propios grupo de procesos como procesos de fondo adecuados. Esto explica el comportamiento observado cuando el shell se cierra antes de algunos de sus trabajos en segundo plano: si entiendo correctamente, cuando se cierra, se envía una señal a los procesos en el mismo grupo de procesos que el shell (por lo que se eliminan los trabajos en segundo plano iniciados set +m), pero no a los de otros grupos de procesos (dejando solo los verdaderos procesos de fondo iniciados en set -m).

Entonces, en su caso, el startup.shscript presumiblemente comienza un trabajo en segundo plano. Cuando esta secuencia de comandos se ejecuta de forma no interactiva, como a través de SSH como en la pregunta a la que se vinculó, el control de trabajo está deshabilitado, el trabajo "en segundo plano" comparte el grupo de procesos del shell remoto y, por lo tanto, se elimina tan pronto como sale del shell. Por el contrario, al habilitar el control del trabajo en ese shell, el trabajo en segundo plano adquiere su propio grupo de procesos y no se elimina cuando sale del shell padre.

dhag
fuente
Gracias por su respuesta, pero ¿cómo se tomcat/bin/startup.shrelaciona con fg/ bg?
laike9m
1
No está directamente relacionado; Estaba tratando de responder "El control de trabajo está habilitado / ¿qué significa esto realmente?" de manera general. Tal vez no lo he dejado claro, pero su script parece comenzar un trabajo en segundo plano, que es a lo que se aplica el resto de mi respuesta.
dhag
2

He encontrado esto en la lista de problemas de github, y creo que esto realmente responde a su pregunta.

No es realmente un problema de SSH, es más el comportamiento sutil en torno a los modos no interactivos / interactivos de BASH y la propagación de la señal a los grupos de procesos.

Lo siguiente se basa en /programming/14679178/why-does-ssh-wait-for-my-subshells-without-t-and-kill-them-with-t/14866774#14866774 y http: //www.itp.uzh.ch/~dpotter/howto/daemonize , con algunos supuestos no completamente validados, pero las pruebas sobre cómo funciona esto parecen confirmar.

pty / tty = falso

El shell bash lanzado se conecta a stdout / stderr / stdin del proceso iniciado y se mantiene en funcionamiento hasta que no haya nada conectado a los sockets y sus hijos hayan salido. Un buen proceso de deamon asegurará que no espere a que salgan sus hijos, bifurque un proceso hijo y luego salga. En este modo, SSH no enviará SIGHUP al proceso secundario. Creo que esto funcionará correctamente para la mayoría de los scripts que ejecutan un proceso que maneja la desamonización y no necesita tener antecedentes. Cuando los scripts de inicio usan '&' para hacer un fondo de un proceso, es probable que el problema principal sea si el proceso en segundo plano alguna vez intenta leer desde stdin ya que eso desencadenará un SIGHUP si la sesión ha finalizado.

pty / tty = verdadero *

Si el script de inicio inicia el proceso, el shell BASH principal devolverá un código de salida a la conexión SSH, que a su vez buscará salir inmediatamente ya que no está esperando que finalice un proceso secundario y no está bloqueado en stdout / stderr / stdin. Esto hará que se envíe un SIGHUP al grupo de procesos de shell bash principal, que dado que el control de trabajo está deshabilitado en modo no interactivo en bash, incluirá los procesos secundarios recién iniciados. Cuando un proceso daemon inicia explícitamente una nueva sesión de proceso cuando se bifurca o en el proceso bifurcado, entonces o sus hijos no recibirán el SIGHUP del proceso padre BASH que sale. Tenga en cuenta que esto es diferente de los trabajos suspendidos que verán un SIGTERM. Sospecho que los problemas relacionados con este funcionamiento solo a veces tienen que ver con una ligera condición de carrera. http://www.itp.uzh.ch/~dpotter/howto/daemonize , verá que en el código la nueva sesión es creada por el proceso bifurcado que no puede ejecutarse antes de que salga el padre, lo que resulta en el azar comportamiento de éxito / falla mencionado anteriormente. Una declaración de suspensión permitirá suficiente tiempo para que el proceso bifurcado haya creado una nueva sesión, por lo que funciona en algunos casos.

pty / tty = verdadero y el control de trabajo está explícitamente habilitado en bash

SSH no se conectará a stdout / stderr / stdin del bash shell ni a ningún proceso hijo iniciado, lo que significará que se cerrará tan pronto como el shell bash primario comience a ejecutar los comandos solicitados. En este caso, con el control de trabajo habilitado explícitamente, cualquier proceso iniciado por el shell bash con '&' para ponerlos en segundo plano se colocará en una sesión separada de inmediato y no recibirá la señal SIGHUP cuando finalice el proceso principal para la sesión BASH ( Conexión SSH en este caso).

Lo que se necesita para arreglar

Creo que las soluciones solo deben mencionarse explícitamente en la documentación de operaciones de ejecución / sudo como un caso especial cuando se trabaja con procesos / servicios en segundo plano. Básicamente, use 'pty = false', o cuando eso no sea posible, habilite explícitamente el control del trabajo como primer comando, y el comportamiento será correcto.

Desde https://github.com/fabric/fabric/issues/395

pootow
fuente