web-dev-qa-db-fra.com

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

Parfois, je veux démarrer un processus et l'oublier. Si je le démarre à partir de la ligne de commande, comme ceci:

redshift

Je ne peux pas fermer le terminal, sinon cela tuera le processus. Puis-je exécuter une commande de manière à pouvoir fermer le terminal sans tuer le processus?

339
Matthew

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:

342
Steven D

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

$ sleep 1000
^Z
[1]+  Stopped                 sleep 1000
$ bg
$ disown
$ exit
147
Stefan

ne bonne réponse est déjà publié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 le terminal fermé, cela supprimera également ces processus enfants. Vous pouvez voir l'arborescence des processus avec pstree, par exemple lorsque vous exécutez kate & à Konsole:

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

Pour séparer le processus kate de konsole lorsque vous terminez konsole, utilisez Nohup avec la commande, comme ceci:

Nohup kate &

Après la fermeture de konsole, pstree ressemblera à ceci:

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

et kate survivra. :)

Une alternative utilise screen/tmux/byobu, qui maintiendra le shell en cours d'exécution, indépendamment du terminal.

50
gertvdijk

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

setsid process

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

31
hanoo

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

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

10
apolinsky

Je préfère:

(Nom de l'application et)

par exemple: [email protected]:~$ (chromium-browser &)

Assurez-vous d'utiliser des parenthèses lorsque vous tapez la commande!

8
daGo

J'ai un script pour:

  • Exécutez 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 l'état de sortie

Je l'utilise principalement pour gedit, evince, inkscape etc qui ont tous beaucoup de sorties de terminaux ennuyeuses. 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
7
jozxyqk

La manière Shell uniquement de faire tout cela est de fermer stdin et d'arrière-plan la commande:

command <&- & 

Ensuite, il ne se fermera pas lorsque vous quitterez le shell. Rediriger stdout est une option facultative intéressante.

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

7
w00t

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
4
tony

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

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

La session peut être déconnectée avec Ctrl ACtrl D et reconnecté dans le cas simple avec screen -r. Je l'ai enveloppé dans un script appelé session qui vit dans mon PATH prê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 "[email protected]; 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. Il ne prévoit pas qu'un programme déjà en cours d'exécution soit déconnecté.

3
roaima

Comme pour les autres réponses publiées précédemment, on peut transférer un processus en cours pour utiliser "screen" rétrospectivement grâce à reptyr puis fermer le terminal. Les étapes sont décrites dans ce post . Les étapes à suivre sont les suivantes:

  1. Suspendre le processus
  2. Reprendre le processus en arrière-plan
  3. Désavouer le processus
  4. Lancer une session écran
  5. Trouver le PID du processus
  6. Utilisez reptyr pour reprendre le processus
2
user308879