Ich verwende '&': Warum läuft der Prozess nicht im Hintergrund?

24

Ich weiß, dass ich &einen Befehl anhängen kann , um den Prozess im Hintergrund auszuführen.

Ich stelle eine SSH-Verbindung zu einer Ubuntu 12.04-Box her und starte ein Python-Programm mit $python program.py &- aber wenn ich das Terminalfenster schließe, erhalte ich die Meldung, dass das Schließen des Terminals den laufenden Prozess abbricht .

Warum ist das? Ich verwende das kaufmännische Und, um den Prozess im Hintergrund auszuführen. Wie kann ich es zum Laufen bringen, unabhängig davon, ob ich in SSH angemeldet bin?

bernie2436
quelle
Duplikat von unix.stackexchange.com/q/4004/69080
Joshua Huber
apt-get install screen, man screen
captcha

Antworten:

51

Wenn Sie ein Terminalfenster schließen, sendet der Terminalemulator ein SIGHUP an den Prozess, den er ausführt, Ihre Shell. Ihre Shell leitet das SIGHUP dann an alles weiter, was ausgeführt wird. Auf Ihrem lokalen System ist dies das ssh. Das SSH leitet das SIGHUP dann an das weiter, was gerade ausgeführt wird, die Remote-Shell. Ihre Remote-Shell sendet dann ein SIGHUP an alle Prozesse, Ihr Hintergrundprogramm.

Es gibt zwei Möglichkeiten, dies zu umgehen.

  1. Trennen Sie das Hintergrundprogramm von Ihrer Shell.
    1. Verwenden Sie den disownBefehl nach dem Hintergrund Ihres Prozesses. Dadurch wird die Shell darüber vergessen.
    2. Stellen Sie Ihrem Befehl nohup( nohup $python program.py &) voran . Dies bewirkt dasselbe, jedoch unter Verwendung eines Zwischenprozesses. Grundsätzlich ignoriert es das SIGHUP-Signal und führt dann das Programm aus, das die Einstellung übernimmt, und beendet es dann. Das gestartete Programm ist kein Kind der Shell, und die Shell weiß nichts darüber. Und wenn kein Signalhandler für SIGHUP installiert wird, wird die Ignorieraktion trotzdem beibehalten.
  2. Verwenden Sie, logoutanstatt das Terminalfenster zu schließen. Wenn Sie verwenden logout, ist dies keine SIGHUP, und die Shell sendet keine SIGHUP an ihre untergeordneten Elemente.

Darüber hinaus müssen Sie sicherstellen, dass Ihr Programm nicht über STDOUT oder STDERR auf das Terminal schreibt, da beide nach dem Beenden des Terminals nicht mehr vorhanden sind. Wenn Sie sie nicht auf etwas umleiten /dev/null, wird das Programm weiterhin ausgeführt, aber wenn es versucht, auf sie zu schreiben, wird ein SIGPIPE ausgegeben, und die Standardaktion von SIGPIPE besteht darin, den Prozess abzubrechen.

Patrick
quelle
4
Technisch gesehen führt das sshSterben dazu , dass die Verbindung unterbrochen wird und die Verbindung sshdam anderen Ende unterbrochen wird. Das SSHD, das die Masterseite des Pseudoterminals steuert, auf dem die Remote-Shell ausgeführt wird, ist ein Auflegen (es ist wie das Ziehen des Steckers an einem realen Terminal), sodass das System ein SIGHUP an die Remote-Shell sendet.
Stéphane Chazelas
@ StéphaneChazelas Das ist eine Sache, mit der ich mich noch nie beschäftigt habe. Wenn es der Kernel ist, der es tut, wie bestimmt er, welcher Prozess zu SIGHUP? Offensichtlich wird nicht alles mit einem offenen Dateideskriptor für dieses TTY überprüft, da Programme so lange ausgeführt werden, wie sie nicht versuchen, es zu verwenden. Wählt es also das Programm aus, das gerade von STDIN liest (da immer nur ein Programm von STDIN lesen kann)?
Patrick
4
Macht nichts, beantwortete meine eigene Frage. POSIX IEEE 1003.1 Kap. 11, Wenn von der Terminalschnittstelle für ein steuerndes Terminal eine Modemtrennung festgestellt wird ... soll das SIGHUP-Signal an den steuernden Prozess gesendet werden .
Patrick
2
Beachten Sie auch, dass nohupeine nohup.outDatei mit der Ausgabe des Programms erstellt wird, mit dem Sie beginnen. Es kann ärgerlich sein, diese Datei jedes Mal zu löschen, wenn Sie nohup zum Starten einer App auf diese Weise verwendet haben (oder wenn Sie die Ausgabe an umleiten müssen /dev/null).
Ruslan
1
Stattdessen nohup python program.py &würde ich setsid python program.pystattdessen empfehlen , was das Programm sofort verleugnet.
Hitechcomputergeek
14

Der Prozess läuft im Hintergrund im Terminal, aber die Ausgabe von stdout(und stderr) wird weiterhin zum Terminal gesendet. Um dies zu beenden, fügen Sie > /dev/null 2>&1vor dem hinzu &, um beide Ausgänge umzuleiten, /dev/nullund stellen Sie disownsicher, dass der Prozess nach dem Schließen des Terminals nicht abgebrochen wird:

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

In Ihrem Fall wäre dies:

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

Der &Bediener trennt Befehle, die parallel ausgeführt werden sollen, genauso wie ;Befehle, die in Reihe ausgeführt werden sollen. Beide Arten von Befehlen werden weiterhin als untergeordnetes Element des Shell-Prozesses ausgeführt .

Wenn Sie also die Shell schließen, die diese Kinder gestartet hat, werden auch die Kinder geschlossen.

Was Sie anscheinend wollen, ist ein Daemon-Prozess , der wesentlich kniffliger ist, da er sich vollständig vom übergeordneten Prozess trennen muss. Die Shell hat normalerweise keine einfache Möglichkeit, dies zu tun.

große Nase
quelle
1

Wenn Sie sich abmelden, werden normalerweise auch die mit der Anmeldesitzung verbundenen Hintergrundprozesse abgebrochen. Wenn Sie möchten, dass sie von der Sitzung getrennt werden, führen Sie sie mit aus nohup.

nohup python program.py &
Barmar
quelle
1

&Führen Sie nach dem mit kaufmännischem Und ( ) endenden Befehl an der Eingabeaufforderung den folgenden Befehl aus bg:

bash> python program.py &  
bash> bg  

Dadurch wird der Befehl "&" in den Hintergrund gestellt

bash> jobs  

Dadurch werden die Jobs aufgelistet, die im Hintergrund ausgeführt werden

bash> fg 1   

Dadurch wird Job 1 in den Vordergrund gerückt

Ein anderer Weg (um sich abmelden zu können)

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

Es können mehrere Zeilen an den atBefehl übergeben werden, bevor das ^ d (Strg-D)
angezeigt wird man at.

martin
quelle