¿Cómo pongo un proceso que ya se está ejecutando en nohup?

940

Tengo un proceso que ya se está ejecutando durante mucho tiempo y no quiero finalizarlo.

¿Cómo lo pongo debajo de nohup (es decir, cómo hago que continúe ejecutándose incluso si cierro el terminal?)

flybywire
fuente
29
Para cualquiera que tenga el mismo problema: recuerde que incluso si escribe yourExecutable &y las salidas siguen apareciendo en la pantalla y Ctrl+Cno parece detener nada, simplemente escriba disown;y presione ciegamente Enterincluso si la pantalla se desplaza con las salidas y no puede ver qué estas escribiendo El proceso será desautorizado y podrá cerrar el terminal sin que el proceso muera.
Nav

Respuestas:

1367

Usando el control de trabajo de bash para enviar el proceso a un segundo plano:

  1. Ctrl+ Zpara detener (pausar) el programa y volver al shell.
  2. bg para ejecutarlo en segundo plano.
  3. disown -h [job-spec]donde [especificación-trabajo] es el número de trabajo (como %1para el primer trabajo en ejecución; encuentre su número con el jobscomando) para que el trabajo no se elimine cuando se cierra el terminal.
Nodo
fuente
38
Como la pregunta era cómo "ponerlo debajo de nohup", disown -htal vez sea la respuesta más exacta: "hacer que Disown se comporte más como nohup (es decir, los trabajos permanecerán en el árbol de proceso de su shell actual hasta que salga de su shell) Esto le permite ver todos los trabajos que comenzó este shell ". (de [ quantprinciple.com/invest/index.php/docs/tipsandtricks/unix/… )
Dr. Jan-Philip Gehrcke
8
¿Cómo recupero el trabajo más tarde? Puedo verlo corriendo usando ps -e.
Paulo Casaretto
26
No puede ver la salida de un trabajo después de que disown, desconocer, hace que un proceso sea un demonio, lo que significa que la entrada / salida estándar se redirige a / dev / null. Entonces, si planea rechazar un trabajo, es mejor comenzar con el inicio de sesión en un archivo, por ejemplomy_job_command | tee my_job.log
rustyx
8
¿es posible de alguna manera hacer algo como 'my_job_command | tee my_job.log ' después de que el comando ya se esté ejecutando?
arod
23
disowndisocia cualquier tubería del proceso. Para volver a conectar las tuberías, use gdbcomo se describe en este hilo . Más específicamente, esta publicación .
mbrownnyc
185

Supongamos que, por alguna razón, Ctrl+ Ztampoco funciona, vaya a otra terminal, busque la identificación del proceso (usando ps) y ejecute:

kill -SIGSTOP PID 
kill -SIGCONT PID

SIGSTOPsuspenderá el proceso y SIGCONTreanudará el proceso, en segundo plano. Entonces, cerrar ambos terminales no detendrá su proceso.

Pungs
fuente
10
Sí, eso es un problema del sistema operativo, kill no funciona con Cygwin en Windows.
Pungs
66
También es muy útil si el trabajo se inicia desde otra sesión ssh.
Amir Ali Akbari
55
Solo recuerde hacer el disown %1en la primera terminal antes de cerrarlo.
Fred
1
Esto es útil ya que comencé una interfaz gráfica con una consola (en mi caso, comencé desde konsole kwindespués de un bloqueo sin pensar en las consecuencias). Entonces, si detuviera a kwin, ¡todo se habría congelado y no tendría posibilidades de correr bg!
Michele
@fred No hice esto y parecía seguir funcionando. ¿Posible o golpeé el PID incorrecto?
Nadie
91

El comando para separar un trabajo en ejecución del shell (= lo hace nohup) es disowny un comando de shell básico.

Desde bash-manpage (man bash):

disown [-ar] [-h] [jobspec ...]

Sin opciones, cada especificación de trabajo se elimina de la tabla de trabajos activos. Si se da la opción -h, cada especificación de trabajo no se elimina de la tabla, sino que se marca para que SIGHUP no se envíe al trabajo si el shell recibe un SIGHUP. Si no hay ninguna especificación de trabajo, y no se proporciona la opción -a ni la opción -r, se utiliza el trabajo actual. Si no se proporciona una especificación de trabajo, la opción -a significa eliminar o marcar todos los trabajos; la opción -r sin un argumento jobspec restringe la operación a trabajos en ejecución. El valor de retorno es 0 a menos que una especificación de trabajo no especifique un trabajo válido.

Eso significa que un simple

disown -a

eliminará todos los trabajos de la tabla de trabajos y los hará nohup

serioys sam
fuente
99
disown -aelimina todos los trabajos. Un simple disownsolo elimina el trabajo actual. Como dice la página del manual en la respuesta.
Rune Schjellerup Philosof
73

Estas son buenas respuestas anteriores, solo quería agregar una aclaración:

No puedes disownun pid o un proceso, eres disownun trabajo, y esa es una distinción importante.

Un trabajo es algo que es una noción de un proceso que se adjunta a un shell, por lo tanto, debe lanzar el trabajo en segundo plano (no suspenderlo) y luego rechazarlo.

Problema:

%  jobs
[1]  running java 
[2]  suspended vi
%  disown %1

Consulte http://www.quantprinciple.com/invest/index.php/docs/tipsandtricks/unix/jobcontrol/ para obtener una discusión más detallada sobre el control de trabajos de Unix.

Caldera Q
fuente
48

Lamentablemente, disownes específico de bash y no está disponible en todos los shells.

Ciertos tipos de Unix (por ejemplo, AIX y Solaris) tienen una opción en el nohupcomando en sí que se puede aplicar a un proceso en ejecución:

nohup -p pid

Ver http://en.wikipedia.org/wiki/Nohup

Valle
fuente
Solo para AIXy Solaris. "Las versiones de nohup de AIX y Solaris tienen una opción -p que modifica un proceso en ejecución para ignorar las señales SIGHUP futuras. A diferencia de lo que se describe anteriormente de bash, nohup -p acepta ID de proceso". Fuente
AlikElzin-kilaka
27

La respuesta de Node es realmente genial, pero dejó abierta la pregunta de cómo se puede redireccionar stdout y stderr. Encontré una solución en Unix y Linux , pero tampoco está completa. Me gustaría fusionar estas dos soluciones. Aquí está:

Para mi prueba, hice un pequeño script bash llamado loop.sh, que imprime el pid de sí mismo con un minuto de sueño en un bucle infinito.

$./loop.sh

Ahora obtenga el PID de este proceso de alguna manera. Por ps -C loop.shlo general, es lo suficientemente bueno, pero está impreso en mi caso.

Ahora podemos cambiar a otro terminal (o presionar ^ Z y en el mismo terminal). Ahora gdbdebe adjuntarse a este proceso.

$ gdb -p <PID>

Esto detiene el script (si se está ejecutando). Se puede verificar su estado ps -f <PID>, donde el STATcampo es 'T +' (o en el caso de ^ Z 'T'), lo que significa (man ps (1))

    T Stopped, either by a job control signal or because it is being traced
    + is in the foreground process group

(gdb) call close(1)
$1 = 0

Cerrar (1) devuelve cero en caso de éxito.

(gdb) call open("loop.out", 01102, 0600)
$6 = 1

Abrir (1) devuelve el nuevo descriptor de archivo si tiene éxito.

Esta apertura es igual a open(path, O_TRUNC|O_CREAT|O_RDWR, S_IRUSR|S_IWUSR). En lugar de O_RDWR O_WRONLYpodría aplicarse, pero /usr/sbin/lsofdice 'u' para todos los controladores de archivos std * ( FDcolumna), que es O_RDWR.

Verifiqué los valores en /usr/include/bits/fcntl.h archivo de encabezado.

El archivo de salida podría abrirse O_APPEND, como nohuplo haría, pero esto no se sugiere man open(2)debido a posibles problemas de NFS.

Si obtenemos -1 como valor de retorno, call perror("")imprime el mensaje de error. Si necesitamos el errno, use p errnogdb comand.

Ahora podemos verificar el archivo recién redirigido. /usr/sbin/lsof -p <PID>huellas dactilares:

loop.sh <PID> truey    1u   REG   0,26        0 15008411 /home/truey/loop.out

Si queremos, podemos redirigir stderr a otro archivo, si queremos usar call close(2)y call open(...)nuevamente usar un nombre de archivo diferente.

Ahora bashse debe liberar el adjunto y podemos salir gdb:

(gdb) detach
Detaching from program: /bin/bash, process <PID>
(gdb) q

Si el script fue detenido por gdbotro terminal, continúa ejecutándose. Podemos volver a la terminal de loop.sh. Ahora no escribe nada en la pantalla, sino que se ejecuta y escribe en el archivo. Tenemos que ponerlo en un segundo plano. Entonces presiona ^Z.

^Z
[1]+  Stopped                 ./loop.sh

(Ahora estamos en el mismo estado que si ^Zse hubiera presionado al principio).

Ahora podemos verificar el estado del trabajo:

$ ps -f 24522
UID        PID  PPID  C STIME TTY      STAT   TIME CMD
<UID>    <PID><PPID>  0 11:16 pts/36   S      0:00 /bin/bash ./loop.sh
$ jobs
[1]+  Stopped                 ./loop.sh

Por lo tanto, el proceso debe ejecutarse en segundo plano y desconectarse de la terminal. El número en la jobssalida del comando entre corchetes identifica el trabajo dentro bash. Podemos usar los siguientes bashcomandos integrados aplicando un signo '%' antes del número de trabajo:

$ bg %1
[1]+ ./loop.sh &
$ disown -h %1
$ ps -f <PID>
UID        PID  PPID  C STIME TTY      STAT   TIME CMD
<UID>    <PID><PPID>  0 11:16 pts/36   S      0:00 /bin/bash ./loop.sh

Y ahora podemos abandonar la llamada de bash. El proceso continúa ejecutándose en segundo plano. Si abandonamos su PPID se convierte en 1 (proceso init (1)) y el terminal de control se vuelve desconocido.

$ ps -f <PID>
UID        PID  PPID  C STIME TTY      STAT   TIME CMD
<UID>    <PID>     1  0 11:16 ?        S      0:00 /bin/bash ./loop.sh
$ /usr/bin/lsof -p <PID>
...
loop.sh <PID> truey    0u   CHR 136,36                38 /dev/pts/36 (deleted)
loop.sh <PID> truey    1u   REG   0,26     1127 15008411 /home/truey/loop.out
loop.sh <PID> truey    2u   CHR 136,36                38 /dev/pts/36 (deleted)

COMENTARIO

El material gdb se puede automatizar creando un archivo (por ejemplo, loop.gdb) que contiene los comandos y ejecutar gdb -q -x loop.gdb -p <PID>. Mi loop.gdb se ve así:

call close(1)
call open("loop.out", 01102, 0600)
# call close(2)
# call open("loop.err", 01102, 0600)
detach
quit

O puede usar el siguiente revestimiento:

gdb -q -ex 'call close(1)' -ex 'call open("loop.out", 01102, 0600)' -ex detach -ex quit -p <PID>

Espero que esta sea una descripción bastante completa de la solución.

Verdad
fuente
Muy informativo, y es probable que funcione bien en casos simples. Pero tenga cuidado, los casos más complejos pueden fallar miserablemente. Tuve uno de esos hoy: mi proceso había generado otro proceso que produjo el resultado (presumiblemente para stderr), pero había conectado stdout para la comunicación con su maestro. La redirección de los FDs maestros no tuvo efecto porque el niño había heredado stderr, y al cerrar la salida estándar del niño falló el maestro que estaba esperando en el otro extremo de la tubería. X- | Bettern conoce bien tus procesos antes de intentarlo.
cmaster - reinstalar a monica el
@cmaster Puede verificar si un identificador se redirige utilizando lsof(el nombre del identificador del archivo es pipe, no como /dev/pts/1) o mediante ls -l /proc/<PID>/fd/<fd>(esto muestra el enlace simbólico del identificador). Además, los subprocesos aún pueden no tener salidas redirigidas, que deberían redirigirse a un archivo.
Verdadero
7

Para enviar el proceso en ejecución a nohup ( http://en.wikipedia.org/wiki/Nohup )

nohup -p pid no me funcionó

Luego probé los siguientes comandos y funcionó muy bien

  1. Ejecute algo de SOMECOMMAND, digamos /usr/bin/python /vol/scripts/python_scripts/retention_all_properties.py 1.

  2. Ctrl+ Zpara detener (pausar) el programa y volver al shell.

  3. bg para ejecutarlo en segundo plano.

  4. disown -h para que el proceso no se elimine cuando se cierra el terminal.

  5. Escriba exitpara salir del shell porque ahora está listo para comenzar, ya que la operación se ejecutará en segundo plano en su propio proceso, por lo que no está vinculada a un shell.

Este proceso es el equivalente a la ejecución nohup SOMECOMMAND.

minhas23
fuente
3

En mi sistema AIX, intenté

nohup -p  processid>

Esto funcionó bien. Continuó ejecutando mi proceso incluso después de cerrar las ventanas de terminal. Tenemos ksh como shell predeterminado, por lo que los comandos bgy disownno funcionaron.

invitado
fuente
2
  1. ctrl+ z - esto pausará el trabajo (¡no se cancelará!)
  2. bg - esto pondrá el trabajo en segundo plano y volverá al proceso de ejecución
  3. disown -a - esto cortará todos los archivos adjuntos con el trabajo (para que pueda cerrar el terminal y aún se ejecutará)

Estos sencillos pasos le permitirán cerrar el terminal mientras mantiene el proceso en ejecución.

No se pondrá nohup(según mi comprensión de su pregunta, no la necesita aquí).

Alper t. Turker
fuente
Creo que el comportamiento de Disown -a es cortar el apego con todos los trabajos. Sin embargo, no cierra las canalizaciones stdin / stdout, lo que significa que el proceso aún intentará escribir (/ leer) desde la terminal
Kelthar
-2

Esto funcionó para mí en Ubuntu Linux mientras estaba en tcshell.

  1. CtrlZ pausarlo

  2. bg correr en segundo plano

  3. jobs para obtener su número de trabajo

  4. nohup %n donde n es el número de trabajo

eshaya
fuente
2
No, no funciona:nohup: failed to run command '%1': No such file or directory
Dunatotatos