Comment puis-je exécuter une commande qui survivra à la fermeture du terminal?

313

Parfois, je veux lancer un processus et l'oublier. Si je le lance à partir de la ligne de commande, comme ceci:

redshift

Je ne peux pas fermer le terminal, sinon cela mettrait fin au processus. Puis-je exécuter une commande de telle manière que je puisse fermer le terminal sans tuer le processus?

Matthieu
la source
4
Ce n'est pas une installation par défaut sur toutes les distributions, mais screen est votre ami: fr.wikipedia.org/wiki/GNU_Screen
Zayne S Halsall
À toutes les personnes confrontées au même problème: rappelez-vous que même si vous tapez yourExecutable &et que les sorties continuent à s'afficher Ctrl+Csans que rien ne semble arrêter, il vous suffit de taper aveuglément disown;et d'appuyer Entermême si l'écran défile avec des sorties et vous ne pouvez pas voir quoi. vous tapez. Le processus sera désavoué et vous pourrez fermer le terminal sans que le processus ne meure.
Nav
Vous pouvez utiliser un multiplexeur d'écran tel que tmux . Il est disponible via apt-get sur les machines Ubuntu
Himanshu

Réponses:

311

L'un des 2 suivants devrait fonctionner:

$ nohup redshift &

ou

$ redshift &
$ disown

Voir ce qui suit pour un peu plus d'informations sur la façon dont cela fonctionne:

Steven D
la source
5
Le second ( redshift & disown) a travaillé pour moi sur Ubuntu 10.10. Il semble bien fonctionner en mettant tout cela sur une seule ligne. Y a-t-il une raison pour laquelle je ne devrais pas faire cela?
Matthieu
4
@Matthew Le premier devrait également fonctionner correctement, il n'a tout simplement pas le même arrière-plan que le second (vous voulez peut-être qu'il en soit nohup redshift &ainsi). Et mettre la seconde sur une ligne est correct, bien que vous sépariez généralement avec ;( redshift &; disown)
Michael Mrozek
10
@ Michael: Les deux ;et &sont des séparateurs de commande et ont la même priorité. La seule différence est l'exécution synchrone par rapport à l'exécution asynchrone (respectivement). Il n'y a pas besoin d'utiliser &;de préférence à juste &(ça marche, mais c'est un peu redondant).
Chris Johnsen
4
bonne réponse, on pourrait ajouter que ce serait une bonne idée de rediriger stdout et stderr afin que le terminal ne soit pas spammé avec une sortie de débogage
Kim
12
En outre, redshift &!désavouer redshift immédiatement.
143

Si votre programme est déjà en cours d' exécution, vous pouvez le suspendre avec Ctrl-Z, tirez-le en arrière-plan avec bget ensuite disown, comme ceci:

$ sleep 1000
^Z
[1]+  Stopped                 sleep 1000
$ bg
$ disown
$ exit
Stefan
la source
3
après désavoir, comment puis-je lire à nouveau la sortie standard du processus en cours?
Necktwi
1
Cela n'a pas fonctionné pour moi pour une raison quelconque (centos)
Ian
Comment tuer le processus après cette procédure?
Palak Darji
2
@necktwi disownne déconnecte pas stdout ou stderr. Cependant nohup, comme pour >/dev/null(déconnexion standard), 2>/dev/null(erreur standard de déconnexion). Il ( disown) déconnecte le contrôle du travail.
ctrl-alt-delor
45

La bonne réponse est déjà postée par @StevenD, mais je pense que cela pourrait clarifier un peu plus.

La raison pour laquelle le processus est tué à la fin du terminal est que le processus que vous démarrez est un processus enfant du terminal. Une fois que vous fermez le terminal, ces processus enfants seront également supprimés. Vous pouvez voir l’arbre de processus avec pstree, par exemple lors de l’exécution kate &de Konsole:

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

Pour que le kateprocessus soit séparé de la konsolefin konsole, utilisez nohupla commande, comme ceci:

nohup kate &

Après la fermeture konsole, pstreeressemblera à ceci:

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

et kateva survivre. :)

Une alternative consiste à utiliser screen/ tmux/ byobu, qui maintiendra le shell en marche, indépendamment du terminal.

Gertvdijk
la source
J'ai eu des problèmes avec les méthodes de désaveu. Cela fonctionne actuellement pour moi, donc upvoting. J'aime aussi ça parce que je peux voir ce qui se passe, mais ne vous inquiétez pas de l'échec de ma session
Ian
27

Vous pouvez exécuter le processus comme ceci dans le terminal

setsid process

Cela lancera le programme dans une nouvelle session. Comme expliqué http://hanoo.org/index.php?article=run-program-in-new-session-linux

hanoo
la source
1
Selon vous, quels sont les avantages de setsid par rapport à nohup?
Itsbruce
1
1) Il n’imprime pas de message gênant nohup.out. 2) Il ne reste pas dans la liste des tâches de votre shell, il n’encombrera donc pas la sortie de jobs.
Mikel
C'est la seule solution qui fonctionne avec un script qui s'exécute dans lxterminal, lance pcmanfm et quitte (avec setsid, le terminal peut se fermer pendant que pcmanfm continue de fonctionner). Merci beaucoup!
desgua
9

Bien que toutes les suggestions fonctionnent bien, j’ai trouvé que mon alternative est d’utiliser screenun programme qui configure un terminal virtuel sur votre écran.

Vous pourriez envisager de commencer avec . Screen peut être installé sur pratiquement tous les dérivés de Linux et Unix. Frapper + et (minuscule) va commencer une deuxième session. Cela vous permettrait de basculer entre la session initiale en appuyant sur + et ou la session plus récente en appuyant sur + et . Vous pouvez avoir jusqu'à dix sessions dans un terminal. J'avais l'habitude de commencer une session au travail, de rentrer chez moi, de ssh dans ma machine de travail, puis d'invoquer . Cela vous reconnectera à cette session à distance.screen -S session_nameCtrlACCtrlA0CtrlA1screen -d -R session_name

Apolinsky
la source
screen -d -m commandva commencer dans l'écran déjà détaché: ~# screen -d -m top ~# screen -ls There is a screen on: 10803..Server-station (Detached) 1 Socket in /root/.screen. ~# screen -x .... et vous êtes.
Dr. Alexander
7

La seule façon de faire tout cela consiste à fermer stdin et à mettre en arrière-plan la commande:

command <&- & 

Ensuite, il ne s’arrêtera pas lorsque vous quitterez le shell. La redirection de stdout est une bonne chose optionnelle à faire.

L'inconvénient est que vous ne pouvez pas le faire après coup.

w00t
la source
J'ai essayé à Ubuntu. Le terminal de mise à mort a également fermé le processus lancé. Une idée sur pourquoi cela pourrait être le cas?
Ashok Koyi
7

J'ai un script pour:

  • Exécuter des commandes arbitraires en arrière-plan

  • Empêchez-les d'être tués avec la fenêtre du terminal

  • Supprimer leur sortie

  • Gère le statut de sortie

Je l' utilise principalement pour gedit, evince, inkscapeetc que tous ont beaucoup de sortie du terminal ennuyeux. Si la commande se termine avant TIMEOUT, l'état de sortie de nohup est renvoyé au lieu de zéro.

#!/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

exemples...

>>> 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
la source
7

Je préfère:

(Nom de l'application &)

par exemple: linux@linux-desktop:~$ (chromium-browser &)

Veillez à utiliser des parenthèses lorsque vous tapez la commande!

daGo
la source
1
La fermeture du terminal mettra fin au processus , ce que nous voulons
absolument
1
Vous avez probablement une commande prompt que j'ai utilisée dans ma réponse sans parenthèses. Si la fermeture du terminal annule le processus, sinon, cela n'arrivera PAS. J'ai déjà édité la solution ci-dessus pour le rendre clair.
daGo
travaille pour moi, tnx
noadev
Je me demande pourquoi cela n'a pas eu plus de votes positifs. nohupempêche toute sortie tty et je voulais juste rediriger la sortie vers un fichier et cela l'empêchait donc c'est la meilleure solution pour moi.
redanimalwar
4

Vous pouvez définir un processus (PID) pour ne pas recevoir de signal HUP lors de la déconnexion et de la fermeture de la session de terminal. Utilisez la commande suivante:

nohup -p PID
tony
la source
3

Sans doute semblable à la réponse offerte par apolinsky , j'utilise une variante sur screen. La commande vanille est comme ça

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

La session peut être déconnectée Ctrl ACtrl Det reconnectée dans le cas simple avec screen -r. J'ai ceci emballé dans un script appelé sessionqui vit dans mon PATHprêt pour un accès pratique:

#!/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

Cela ne fonctionne que si vous savez à l'avance que vous souhaitez déconnecter un programme. Cela ne permet pas de déconnecter un programme en cours d'exécution .

Roaima
la source
2

De la même manière que les réponses précédentes, il est possible de transférer un processus en cours pour utiliser "screen" rétrospectivement grâce à reptyr , puis de fermer le terminal. Les étapes sont décrites dans ce post . Les étapes à suivre sont:

  1. Suspendre le processus
  2. Reprendre le processus en arrière-plan
  3. Désavouer le processus
  4. Lancer une session d'écran
  5. Trouver le PID du processus
  6. Utilisez reptyr pour prendre en charge le processus
utilisateur308879
la source