Estoy usando `&`: ¿por qué el proceso no se ejecuta en segundo plano?

24

Sé que puedo agregar &un comando para ejecutar el proceso en segundo plano.

Estoy ingresando en un cuadro de Ubuntu 12.04 y ejecuto un programa de Python con $python program.py &, pero cuando cierro la ventana del terminal recibo un mensaje que dice que cerrar el terminal matará el proceso en ejecución.

¿Por qué es esto? Estoy usando el ampersand para ejecutar el proceso en segundo plano. ¿Cómo puedo hacer que se ejecute independientemente de si estoy en SSH?

bernie2436
fuente
Duplicado de unix.stackexchange.com/q/4004/69080
Joshua Huber
apt-get install screen, man screen
captcha

Respuestas:

51

Cuando cierra una ventana de terminal, el emulador de terminal envía un SIGHUP al proceso que está ejecutando, su shell. Su shell luego reenvía ese SIGHUP a todo lo que está ejecutando. En su sistema local, este es el ssh. El ssh luego reenvía el SIGHUP a lo que está ejecutando, el shell remoto. Entonces, su shell remoto envía un SIGHUP a todos sus procesos, su programa en segundo plano.

Hay 2 formas de evitar esto.

  1. Desasociar el programa de fondo de su shell.
    1. Utilizar el disown comando después de poner en segundo plano su proceso. Esto hará que el shell lo olvide.
    2. Prefije su comando con nohup(nohup $python program.py & ). Esto logra lo mismo, pero mediante el uso de un proceso intermedio. Básicamente, ignora la señal SIGHUP, y luego bifurca y ejecuta su programa que hereda la configuración, y luego sale. Debido a que se bifurcó, el programa que se está iniciando no es hijo del shell, y el shell no lo sabe. Y a menos que instale un controlador de señal para SIGHUP, mantiene la acción de ignorar de todos modos.
  2. Use en logoutlugar de cerrar la ventana de terminal. Cuando lo usa logout, esto no es un SIGHUP, por lo que el shell no enviará un SIGHUP a ninguno de sus hijos.

Además, debe asegurarse de que su programa no escriba en el terminal a través de STDOUT o STDERR, ya que ambos ya no existirán una vez que el terminal salga. Si no los redirige a algo como /dev/null, el programa aún se ejecutará, pero si intenta escribirles, obtendrá un SIGPIPE, y la acción predeterminada de SIGPIPE es matar el proceso).

Patricio
fuente
44
Técnicamente, sshmorir hace que la conexión se caiga, la conexión a la caída hace sshdque muera el otro extremo. Ese sshd que controla el lado maestro del pseudo-terminal que ejecuta el shell remoto, cuando muere, es un bloqueo (es como desconectar un terminal real), por lo que el sistema envía un SIGHUP al shell remoto.
Stéphane Chazelas
@ StéphaneChazelas Eso es algo en lo que nunca he cavado. Si es el núcleo que lo hace, ¿cómo determina qué proceso realizar SIGHUP? Obviamente no SIGHUP todo con un descriptor de archivo abierto para ese TTY, ya que los programas seguirán ejecutándose mientras no intenten usarlo. Entonces, ¿elige el programa que está leyendo actualmente desde STDIN (ya que solo uno puede leer desde STDIN a la vez)?
Patrick
44
No importa, respondió mi propia pregunta. POSIX IEEE 1003.1 cap 11, Si la interfaz del terminal detecta una desconexión del módem para un terminal de control ... la señal SIGHUP se enviará al proceso de control .
Patrick
2
También tenga en cuenta que nohupgenera un nohup.outarchivo con salida del programa que comienza con él. Puede ser molesto eliminar ese archivo cada vez que ha usado nohup para iniciar una aplicación de esta manera (o necesitaría redirigir su salida a /dev/null).
Ruslan
1
En lugar de nohup python program.py &recomendaría usar en su setsid python program.pylugar, lo que anula inmediatamente el programa.
Hitechcomputergeek
14

El proceso se ejecuta en segundo plano en el terminal, pero la salida de stdout(y stderr) todavía se envía al terminal. Para detener esto, agregue > /dev/null 2>&1antes &de redirigir ambas salidas a /dev/null- agregar disowntambién asegura que el proceso no se elimine después de cerrar el terminal:

COMMAND > /dev/null 2>&1 & disown

En su caso esto sería:

python program.py > /dev/null 2>&1 & disown
Wilf
fuente
3

El &operador separa los comandos para ejecutar en paralelo, al igual que ;separa los comandos para ejecutar en serie. Ambos tipos de comandos aún se ejecutarán como elementos secundarios del proceso de shell .

Por lo tanto, cuando cierre el shell que inició esos niños, los niños también se cerrarán.

Lo que parece querer es un proceso de demonio , que es significativamente más complicado porque necesita disociarse por completo del proceso padre. El shell generalmente no tiene una forma simple de hacerlo.

nariz grande
fuente
1

Cuando cierra la sesión, los procesos en segundo plano asociados con la sesión de inicio de sesión normalmente también se eliminan. Si desea que se desconecten de la sesión, ejecútelos con nohup.

nohup python program.py &
Barmar
fuente
1

Después del comando que termina con ampersand ( &), en el símbolo del sistema, ejecute el comando bg:

bash> python program.py &  
bash> bg  

Esto pondrá el comando "&" en segundo plano.

bash> jobs  

Esto enumerará los trabajos que se ejecutan en segundo plano.

bash> fg 1   

Esto traerá el trabajo # 1 al primer plano

Otra forma, (para poder cerrar sesión)

bash> at now  
bash> /full/path/python /full/path/program.py  
bash> ^d   `(# That is, Control-D, to run the command, Control-C to cancel)`  

Se pueden enviar varias líneas al atcomando, antes de que
vea ^ d (Control-D) man at.

martín
fuente