web-dev-qa-db-fra.com

J'utilise `&`: pourquoi le processus ne s'exécute-t-il pas en arrière-plan?

Je sais que je peux ajouter & à une commande pour exécuter le processus en arrière-plan.

Je suis SSH dans une boîte Ubuntu 12.04 et j'exécute un programme python avec $python program.py & - mais quand je vais fermer la fenêtre du terminal, je reçois un message disant que la fermeture du terminal tuera le processus en cours.

Pourquoi est-ce? J'utilise l'esperluette pour exécuter le processus en arrière-plan. Comment puis-je le faire fonctionner, que je sois SSH ou non?

27
bernie2436

Lorsque vous fermez une fenêtre de terminal, l'émulateur de terminal envoie un SIGHUP au processus qu'il exécute, votre Shell. Votre Shell transmet ensuite ce SIGHUP à tout ce qu'il exécute. Sur votre système local, c'est le ssh. Le ssh transmet ensuite le SIGHUP à ce qu'il exécute, le shell distant. Votre Shell distant envoie alors un SIGHUP à tous ses processus, votre programme en arrière-plan.

Il y a 2 façons de contourner cela.

  1. Dissociez le programme en arrière-plan de votre shell.
    1. Utilisez la commande disown après avoir mis en arrière-plan votre processus. Cela fera oublier le Shell.
    2. Préfixez votre commande avec Nohup (Nohup $python program.py &). Cela accomplit la même chose, mais en utilisant un processus intermédiaire. Fondamentalement, il ignore le signal SIGHUP, puis exécute et exécute votre programme qui hérite du paramètre, puis quitte. Parce qu'il a bifurqué, le programme en cours de lancement n'est pas un enfant du Shell, et le Shell ne le sait pas. Et à moins qu'il n'installe un gestionnaire de signaux pour SIGHUP, il conserve quand même l'action ignorer.
  2. Utilisez logout au lieu de fermer la fenêtre du terminal. Lorsque vous utilisez logout, ce n'est pas un SIGHUP, et donc le Shell n'enverra aucun SIGHUP à aucun de ses enfants.

De plus, vous devez vous assurer que votre programme n'écrit pas sur le terminal via STDOUT ou STDERR, car les deux n'existeront plus une fois le terminal fermé. Si vous ne les redirigez pas vers quelque chose comme /dev/null, le programme fonctionnera toujours, mais s'il essaie de leur écrire, il obtiendra un SIGPIPE, et l'action par défaut de SIGPIPE est de tuer le processus).

53
Patrick

Le processus s'exécute en arrière-plan dans le terminal, mais la sortie de stdout (et stderr) est toujours envoyée au terminal. Pour arrêter cela, ajoutez > /dev/null 2>&1 avant le & pour rediriger les deux sorties vers /dev/null - l'ajout de disown garantit également que le processus n'est pas interrompu après la fermeture du terminal:

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

Dans votre cas, ce serait:

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

Le & L'opérateur sépare les commandes à exécuter en parallèle, tout comme ; sépare les commandes à exécuter en série. Les deux types de commandes seront toujours exécutés en tant qu'enfant du processus Shell.

Ainsi, lorsque vous fermerez le Shell qui a démarré ces enfants, les enfants seront également fermés.

Ce que vous semblez vouloir, c'est un processus démon , ce qui est beaucoup plus délicat car il doit se dissocier entièrement du processus parent. Le Shell n'a généralement pas de moyen simple de le faire.

4
bignose

Lorsque vous vous déconnectez, les processus d'arrière-plan associés à la session de connexion sont également normalement supprimés. Si vous souhaitez qu'ils soient déconnectés de la session, exécutez-les avec Nohup.

Nohup python program.py &
1
Barmar

Après la commande se terminant par esperluette (&), à l'invite de commandes, exécutez la commande bg:

bash> python program.py &  
bash> bg  

Cela mettra la commande "&" en arrière-plan

bash> jobs  

Cela répertoriera les travaux en cours d'exécution en arrière-plan

bash> fg 1   

Cela mettra Job # 1 au premier plan

Une autre façon, (pour pouvoir vous déconnecter)

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)`  

Plusieurs lignes peuvent être soumises à la commande at, avant le ^ d (Control-D)
voir man at.

1
martin