Sto usando `&`: perché il processo non è in esecuzione in background?


24

So che posso aggiungere &un comando per eseguire il processo in background.

Sto entrando in una scatola Ubuntu 12.04 e sto eseguendo un programma Python con $python program.py &- ma quando vado a chiudere la finestra del terminale ricevo un messaggio che dice che chiudere il terminale ucciderà il processo in esecuzione.

Perchè è questo? Sto usando la e commerciale per eseguire il processo in background. Come posso farlo funzionare indipendentemente dal fatto che io sia SSH?



schermata di installazione apt-get, schermata man
captcha

Risposte:


51

Quando chiudi una finestra di terminale, l'emulatore di terminale invia un SIGHUP al processo che sta eseguendo, la tua shell. La tua shell quindi inoltra quel SIGHUP a tutto ciò che sta funzionando. Sul tuo sistema locale, questo è lo ssh. Lo ssh quindi inoltra il SIGHUP a ciò che sta eseguendo, la shell remota. Quindi la tua shell remota invia quindi un SIGHUP a tutti i suoi processi, il tuo programma in background.

Ci sono 2 modi per aggirare questo.

  1. Dissocia il programma in background dalla shell.
    1. Utilizzare il disowncomando dopo aver eseguito il background del processo. Questo farà dimenticare la shell.
    2. Prefisso il tuo comando con nohup( nohup $python program.py &). Questo compie la stessa cosa, ma usando un processo intermedio. Fondamentalmente ignora il segnale SIGHUP, quindi esegue il fork e esegue il programma che eredita l'impostazione, quindi esce. Poiché è stato biforcato, il programma che viene avviato non è figlio della shell e la shell non lo sa. E a meno che non installi un gestore di segnali per SIGHUP, mantiene comunque l'azione ignora.
  2. Utilizzare logoutinvece di chiudere la finestra del terminale. Quando lo usi logout, questo non è un SIGHUP, quindi la shell non invierà un SIGHUP a nessuno dei suoi figli.

Inoltre, è necessario assicurarsi che il programma non scriva sul terminale tramite STDOUT o STDERR, poiché entrambi questi non esisteranno più una volta terminato il terminale. Se non li reindirizzi a qualcosa del genere /dev/null, il programma verrà comunque eseguito, ma se tenta di scrivere su di essi, otterrà un SIGPIPE e l'azione predefinita di SIGPIPE è quella di terminare il processo).


4
Tecnicamente, la sshmorte provoca la caduta della connessione, mentre la connessione a caduta provoca sshdla morte dell'altra estremità. Quel sshd che controlla il lato master dello pseudo-terminale che esegue la shell remota, quando muore, è un blocco (è come tirare la spina su un terminale reale), quindi il sistema invia un SIGHUP alla shell remota.
Stéphane Chazelas,

@ StéphaneChazelas Questa è una cosa che non ho mai scavato. Se è il kernel a farlo, come determina quale processo eseguire SIGHUP? Ovviamente non SIGHUP tutto con un descrittore di file aperto a quel TTY, poiché i programmi rimarranno in esecuzione fino a quando non tenteranno di usarlo. Quindi sceglie il programma che sta attualmente leggendo da STDIN (dal momento che solo uno può leggere da STDIN alla volta)?
Patrick,

4
Non importa, ha risposto alla mia domanda. POSIX IEEE 1003.1 cap 11, Se viene rilevata una disconnessione del modem dall'interfaccia del terminale per un terminale di controllo ... il segnale SIGHUP deve essere inviato al processo di controllo .
Patrick,

2
Si noti inoltre che nohupgenera un nohup.outfile con l'output del programma che si inizia con esso. Potrebbe essere fastidioso eliminare quel file ogni volta che hai usato nohup per avviare un'app in questo modo (o dovresti reindirizzare il suo output su /dev/null).
Ruslan,

1
Invece di nohup python program.py &raccomandare di utilizzare setsid python program.pyinvece, che rinnega immediatamente il programma.
Hitechcomputergeek,

14

Il processo è in esecuzione in background nel terminale, ma l'output da stdout(e stderr) viene ancora inviato al terminale. Per fermarlo, aggiungi > /dev/null 2>&1prima &di reindirizzare entrambi gli output a /dev/null- l'aggiunta disownassicura anche che il processo non venga interrotto dopo aver chiuso il terminale:

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

Nel tuo caso questo sarebbe:

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

3

L' &operatore separa i comandi da eseguire in parallelo, così come ;separa i comandi da eseguire in serie. Entrambi i tipi di comandi verranno comunque eseguiti come figlio del processo di shell .

Quindi, quando chiudi il guscio che ha avviato quei bambini, anche i bambini saranno chiusi.

Ciò che sembra desiderare è un processo daemon , che è significativamente più complicato perché deve dissociarsi completamente dal processo genitore. La shell di solito non ha un modo semplice per farlo.


1

Quando si effettua il logout, anche i processi in background associati alla sessione di login vengono normalmente eliminati. Se si desidera che vengano disconnessi dalla sessione, eseguirli con nohup.

nohup python program.py &

1

Dopo il comando che termina con e commerciale ( &), al prompt dei comandi eseguire il comando bg:

bash> python program.py &  
bash> bg  

Questo metterà il comando "&" sullo sfondo

bash> jobs  

Questo elencherà i lavori in esecuzione in background

bash> fg 1   

Ciò porterà in primo piano il lavoro n. 1

Un altro modo, (per essere in grado di disconnettersi)

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

Linee multiple possono essere presentate al atcomando, prima del ^ D (Control-D)
vedono man at.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.