¿Cómo puedo ejecutar un comando que sobrevivirá al cierre de la terminal?

313

A veces quiero comenzar un proceso y olvidarlo. Si lo inicio desde la línea de comando, así:

redshift

No puedo cerrar la terminal, o matará el proceso. ¿Puedo ejecutar un comando de tal manera que pueda cerrar el terminal sin matar el proceso?

Mateo
fuente
44
No es una instalación predeterminada en todas las distribuciones, pero la pantalla es tu amiga: en.wikipedia.org/wiki/GNU_Screen
Zayne S Halsall el
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 la terminal sin que el proceso muera.
Nav
Puede usar el multiplexor de pantalla como tmux . Está disponible a través de apt-get en máquinas ubuntu
Himanshu

Respuestas:

311

Uno de los siguientes 2 debería funcionar:

$ nohup redshift &

o

$ redshift &
$ disown

Consulte lo siguiente para obtener un poco más de información sobre cómo funciona esto:

Steven D
fuente
55
El segundo ( redshift & disown) funcionó para mí en Ubuntu 10.10. Parece funcionar bien poner todo en una línea. ¿Hay alguna razón por la que no debería hacer esto?
Mateo
44
@Matthew El primero también debería funcionar bien, simplemente no tiene fondo como el segundo (posiblemente lo desees, nohup redshift &por lo que lo hace de fondo). Y poner el segundo en una línea está bien, aunque generalmente se separa con ;( redshift &; disown)
Michael Mrozek
10
@ Michael: Ambos ;y &son separadores de comandos y tienen la misma precedencia. La única diferencia es la ejecución síncrona versus asíncrona (respectivamente). No es necesario usarlo &;con preferencia &(solo funciona, pero es un poco redundante).
Chris Johnsen el
44
buena respuesta, uno podría agregar que sería una buena idea redirigir stdout y stderr para que el terminal no sea enviado spam con salida de depuración
Kim
12
Además, redshift &!desconocerá el desplazamiento al rojo inmediatamente.
143

Si su programa ya se está ejecutando , puede pausarlo Ctrl-Z, ponerlo en segundo plano con bgy luego disown, de esta manera:

$ sleep 1000
^Z
[1]+  Stopped                 sleep 1000
$ bg
$ disown
$ exit
Stefan
fuente
3
después de desconocer, ¿cómo puedo volver a leer el stdout del proceso en ejecución?
Necktwi
1
Esto no funcionó para mí por alguna razón (centos)
Ian
¿Cómo matar el proceso después de este procedimiento?
Palak Darji
2
@necktwi disownno desconecta stdout o stderr. Sin nohupembargo, al igual que >/dev/null(desconecta la salida estándar), 2>/dev/null(desconecta el error estándar). ( disown) Desconecta el control de trabajo.
ctrl-alt-delor
45

@StevenD ya ha publicado una buena respuesta, pero creo que esto podría aclararlo un poco más.

La razón por la que el proceso se interrumpe al terminar el terminal es porque el proceso que inicia es un proceso secundario del terminal. Una vez que cierre la terminal, esto también eliminará estos procesos secundarios. Puede ver el árbol de procesos con pstree, por ejemplo, cuando se ejecuta kate &en Konsole:

init-+
     ├─konsole─┬─bash─┬─kate───2*[{kate}]
     │         │      └─pstree
     │         └─2*[{konsole}]

Para hacer que el kateproceso se separe de konsolecuando termina konsole, use nohupcon el comando, así:

nohup kate &

Después del cierre konsole, pstreese verá así:

init-+
     |-kate---2*[{kate}]

y katesobrevivirá :)

Una alternativa es usar screen/ tmux/ byobu, que mantendrá el shell en ejecución, independientemente del terminal.

gertvdijk
fuente
Tuve problemas con los métodos desconocidos. Esto está funcionando actualmente para mí, por lo que estoy votando. También me gusta esto porque puedo seguir -f nohup.out para ver qué sucede, pero no preocuparme por el fracaso de mi sesión
Ian
27

Puedes ejecutar el proceso así en la terminal

setsid process

Esto ejecutará el programa en una nueva sesión. Como se explica http://hanoo.org/index.php?article=run-program-in-new-session-linux

hanoo
fuente
1
¿Cuáles ves como las ventajas de setsid sobre nohup?
itsbruce
1
1) No imprime un mensaje molesto sobre nohup.out. 2) No permanece en la lista de trabajos de su shell, por lo que no satura la salida de jobs.
Mikel
Esta es la única solución que funcionó con un script que se ejecuta en lxterminal, inicia pcmanfm y sale (con setsid el terminal puede cerrarse mientras pcmanfm sigue ejecutándose). Muchas gracias!
Desgua
9

Aunque todas las sugerencias funcionan bien, he encontrado que mi alternativa es usar screenun programa que configura un terminal virtual en su pantalla.

Puede considerar comenzarlo con . Screen se puede instalar en prácticamente todos los derivados de Linux y Unix. Al presionar + y (minúsculas) comenzará una segunda sesión. Esto le permitirá alternar entre la sesión inicial presionando + y / o la sesión más nueva presionando + y . Puede tener hasta diez sesiones en una terminal. Solía ​​comenzar una sesión en el trabajo, ir a casa, ingresar a mi máquina de trabajo y luego invocar . Esto lo reconectará a esa sesión remota.screen -S session_nameCtrlACCtrlA0CtrlA1screen -d -R session_name

apolinsky
fuente
screen -d -m commandlo iniciará dentro de la pantalla ya separada: ~# screen -d -m top ~# screen -ls There is a screen on: 10803..Server-station (Detached) 1 Socket in /root/.screen. ~# screen -x ... y ya está.
Dr. Alexander
7

La forma única de hacer todo esto es cerrar stdin y poner en segundo plano el comando:

command <&- & 

Entonces no se cerrará cuando salga del shell. Redirigir stdout es una buena opción opcional para hacer.

La desventaja es que no puedes hacer esto después del hecho.

w00t
fuente
Lo intenté en ubuntu. La terminal de asesinatos también cerró el proceso lanzado. ¿Alguna idea de por qué este podría ser el caso?
Ashok Koyi
7

Tengo un script para:

  • Ejecute comandos arbitrarios en segundo plano

  • Evita que sean asesinados con la ventana de terminal

  • Suprimir su salida

  • Maneja el estado de salida

Lo uso principalmente para gedit, etc. evince, inkscapeque tienen mucha salida de terminal molesta. Si el comando termina antes TIMEOUT, se devuelve el estado de salida de nohup en lugar de cero.

#!/bin/bash

TIMEOUT=0.1

#use nohup to run the command, suppressing its output and allowing the terminal to be closed
#also send nohup's output to /dev/null, supressing nohup.out
#run nohup in the background so this script doesn't block
nohup "${@}" >/dev/null 2>&1 &
NOHUP_PID=$!

#kill this script after a short time, exiting with success status - command is still running
#this is needed as there is no timeout argument for `wait` below
MY_PID=$$
trap "exit 0" SIGINT SIGTERM
sleep $TIMEOUT && kill $MY_PID 2>/dev/null & #ignore "No such process" error if this exits normally

#if the command finishes before the above timeout, everything may be just fine or there could have been an error
wait $NOHUP_PID
NOHUP_STATUS=$?
#print an error if there was any. most commonly, there was a typo in the command
[ $NOHUP_STATUS != 0 ] && echo "Error ${@}"
#return the exit status of nohup, whatever it was
exit $NOHUP_STATUS

ejemplos ...

>>> run true && echo success || echo fail
success
>>> run false && echo success || echo fail
Error false
fail
>>> run sleep 1000 && echo success || echo fail
success
>>> run notfound && echo success || echo fail
Error notfound
fail
jozxyqk
fuente
7

Yo prefiero:

(Nombre de la aplicación &)

por ejemplo: linux@linux-desktop:~$ (chromium-browser &)

¡Asegúrese de usar paréntesis cuando escriba el comando!

extranjero
fuente
1
Cerrar el terminal matará el proceso , que es exactamente lo que OP (y yo, por lo tanto, aquí) queremos evitar
gromit190
1
Probablemente tenga un comando rápido que he usado en mi respuesta sin paréntesis, si es así, cerrar el terminal matará el proceso, de lo contrario NO sucederá. Ya he editado la solución anterior para que quede claro.
daGo
trabaja para mí, tnx
noadev
Me pregunto por qué esto no recibió más votos a favor. nohupevita cualquier salida de tty y en realidad solo quería redirigir la salida a un archivo y lo evitó, por lo que esta es la mejor solución para mí.
redanimalwar
4

Puede configurar un proceso (PID) para que no reciba una señal HUP al cerrar sesión y cerrar la sesión del terminal. Use el siguiente comando:

nohup -p PID
Tony
fuente
3

Posiblemente similar a la respuesta ofrecida por apolinsky , utilizo una variante en screen. El comando vainilla es así

screen bash -c 'long_running_command_here; echo; read -p "ALL DONE:"'

La sesión se puede desconectar Ctrl ACtrl Dy volver a conectar en el caso simple con screen -r. Tengo esto envuelto en un script llamado sessionque vive en mi PATHlista para un acceso conveniente:

#!/bin/bash
#
if screen -ls | awk '$1 ~ /^[1-9][0-9]*\.'"$1"'/' >/dev/null
then
    echo "WARNING: session is already running (reattach with 'screen -r $1')" >&2
else
    exec screen -S "$1" bash -c "$@; echo; echo '--------------------'; read -p 'ALL DONE (Enter to exit):'"
    echo "ERROR: 'screen' is not installed on this system" >&2
fi
exit 1

Esto solo funciona cuando sabe de antemano que desea desconectar un programa. No proporciona la desconexión de un programa que ya se está ejecutando .

roaima
fuente
2

De manera similar a otras respuestas publicadas anteriormente, uno puede transferir un proceso en ejecución para usar "pantalla" retrospectivamente gracias a reptyr y luego cerrar el terminal. Los pasos se describen en esta publicación . Los pasos a seguir son:

  1. Suspender el proceso
  2. Reanudar el proceso en segundo plano
  3. Desconoce el proceso
  4. Lanzar una sesión de pantalla
  5. Encuentra el PID del proceso
  6. Use reptyr para hacerse cargo del proceso
usuario308879
fuente