Wie stelle ich einen bereits laufenden Prozess unter nohup?

940

Ich habe einen Prozess, der bereits lange läuft und möchte ihn nicht beenden.

Wie setze ich es unter nohup (das heißt, wie lasse ich es weiterlaufen, selbst wenn ich das Terminal schließe?)

Flybywire
quelle
29
Für alle, die mit dem gleichen Problem konfrontiert sind: Denken Sie daran, dass Sie, selbst wenn Sie tippen yourExecutable &und die Ausgaben weiterhin auf dem Bildschirm erscheinen und Ctrl+Cnichts zu stoppen scheinen, einfach blind tippen disown;und drücken, Enterselbst wenn der Bildschirm mit den Ausgaben scrollt und Sie nicht sehen können, was Sie tippen. Der Prozess wird abgelehnt und Sie können das Terminal schließen, ohne dass der Prozess stirbt.
Nav

Antworten:

1367

Verwenden der Jobsteuerung von bash, um den Prozess in den Hintergrund zu stellen:

  1. Ctrl+ Zum das Programm anzuhalten (anzuhalten) und zur Shell zurückzukehren.
  2. bg um es im Hintergrund auszuführen.
  3. disown -h [job-spec]Dabei ist [Jobspezifikation] die Jobnummer (wie %1beim ersten ausgeführten Job; ermitteln Sie Ihre Nummer mit dem jobsBefehl), damit der Job beim Schließen des Terminals nicht beendet wird.
Knoten
quelle
38
Da die Frage lautete, wie man es unter "nohup" stellt, disown -hlautet die genauere Antwort: "Verleugnung verhalten sich eher wie nohup (dh die Jobs bleiben im Prozessbaum Ihrer aktuellen Shell, bis Sie Ihre Shell verlassen). Dies ermöglicht es Ihnen zu sehen alle Jobs, die diese Shell gestartet hat. " (von [ quantprinciple.com/invest/index.php/docs/tipsandtricks/unix/… )
Dr. Jan-Philip Gehrcke
8
Wie kann ich den Job später wiederherstellen? Ich kann es mit ps -e laufen sehen.
Paulo Casaretto
26
Sie können die Ausgabe eines Jobs nicht sehen, nachdem disowndisown einen Prozess zu einem Daemon gemacht hat. Dies bedeutet, dass die Standardeingabe / -ausgabe nach / dev / null umgeleitet wird. Wenn Sie also vorhaben, einen Job my_job_command | tee my_job.log
abzulehnen
8
ist es irgendwie möglich so etwas wie 'my_job_command | zu machen tee my_job.log ' nachdem der Befehl bereits ausgeführt wird?
Arod
23
disownTrennt alle Rohre vom Prozess. Verwenden Sie gdbzum Wiederanbringen von Rohren wie in diesem Gewinde beschrieben . Genauer gesagt, dieser Beitrag .
mbrownnyc
185

Angenommen, aus irgendeinem Grund Ctrl+ Zfunktioniert auch nicht, gehen Sie zu einem anderen Terminal, suchen Sie die Prozess-ID (using ps) und führen Sie Folgendes aus:

kill -SIGSTOP PID 
kill -SIGCONT PID

SIGSTOPwird den Prozess SIGCONTanhalten und den Prozess im Hintergrund fortsetzen. Wenn Sie jetzt beide Terminals schließen, wird Ihr Prozess nicht gestoppt.

Pungs
quelle
10
Ja, das ist ein Betriebssystemproblem. Kill funktioniert nicht mit Cygwin unter Windows.
Pungs
6
Auch sehr nützlich, wenn der Job von einer anderen SSH-Sitzung aus gestartet wird.
Amir Ali Akbari
5
Denken Sie daran, dies disown %1im ersten Terminal zu tun, bevor Sie es schließen.
Fred
1
Dies ist nützlich, da ich eine grafische Oberfläche mit einer Konsole gestartet habe (in meinem Fall habe ich kwinnach einem Absturz von der Konsole aus gestartet, ohne an die Konsequenzen zu denken). Wenn ich also kwin gestoppt hätte, wäre alles eingefroren und ich hätte keine Möglichkeit zu rennen bg!
Michele
@fred Ich habe das nicht gemacht und es schien weiter zu laufen. Möglich oder habe ich die falsche PID getroffen?
Niemand
91

Der Befehl zum Trennen eines laufenden Jobs von der Shell (= macht ihn nohup) ist disownund ein grundlegender Shell-Befehl.

Aus der Bash-Manpage (Man Bash):

disown [-ar] [-h] [jobspec ...]

Ohne Optionen wird jede Jobspezifikation aus der Tabelle der aktiven Jobs entfernt. Wenn die Option -h angegeben ist, wird nicht jede Jobspezifikation aus der Tabelle entfernt, sondern markiert, damit SIGHUP nicht an den Job gesendet wird, wenn die Shell ein SIGHUP empfängt. Wenn keine Jobspezifikation vorhanden ist und weder die Option -a noch die Option -r angegeben sind, wird der aktuelle Job verwendet. Wenn keine Jobspezifikation angegeben ist, bedeutet die Option -a, alle Jobs zu entfernen oder zu markieren. Die Option -r ohne das Argument jobspec beschränkt den Betrieb auf die Ausführung von Jobs. Der Rückgabewert ist 0, es sei denn, eine Jobspezifikation gibt keinen gültigen Job an.

Das heißt, dass eine einfache

disown -a

entfernt alle Jobs aus der Jobtabelle und macht sie nohup

serioys sam
quelle
9
disown -aentfernt alle Jobs. Ein einfaches disownentfernt nur den aktuellen Job. Wie die Manpage in der Antwort sagt.
Rune Schjellerup Philosof
73

Dies sind gute Antworten oben, ich wollte nur eine Klarstellung hinzufügen:

Sie können nicht disownpid oder verarbeiten, Sie sind disownein Job, und das ist eine wichtige Unterscheidung.

Ein Job ist eine Vorstellung von einem Prozess, der an eine Shell angehängt ist. Daher müssen Sie den Job in den Hintergrund werfen (nicht aussetzen) und ihn dann ablehnen.

Problem:

%  jobs
[1]  running java 
[2]  suspended vi
%  disown %1

Weitere Informationen zur Unix-Jobsteuerung finden Sie unter http://www.quantprinciple.com/invest/index.php/docs/tipsandtricks/unix/jobcontrol/ .

Q Kessel
quelle
48

Ist leider disownspezifisch für Bash und nicht in allen Shells verfügbar.

Bestimmte Unix-Varianten (z. B. AIX und Solaris) verfügen über eine Option im nohupBefehl selbst, die auf einen laufenden Prozess angewendet werden kann:

nohup -p pid

Siehe http://en.wikipedia.org/wiki/Nohup

Tal
quelle
Nur für AIXund Solaris. "Die AIX- und Solaris-Versionen von nohup verfügen über die Option -p, mit der ein laufender Prozess so geändert wird, dass zukünftige SIGHUP-Signale ignoriert werden. Im Gegensatz zu dem oben beschriebenen nicht verleugneten Build von bash akzeptiert nohup -p Prozess-IDs." Quelle
AlikElzin-kilaka
27

Die Antwort von Node ist wirklich großartig, aber es blieb die Frage offen, wie stdout und stderr umgeleitet werden können. Ich habe eine Lösung unter Unix und Linux gefunden , die aber auch nicht vollständig ist. Ich möchte diese beiden Lösungen zusammenführen. Hier ist es:

Für meinen Test habe ich ein kleines Bash-Skript namens loop.sh erstellt, das die PID von sich selbst mit einer Minute Schlaf in einer Endlosschleife druckt.

$./loop.sh

Holen Sie sich jetzt irgendwie die PID dieses Prozesses. Normalerweise ps -C loop.shist es gut genug, aber es ist in meinem Fall gedruckt.

Jetzt können wir zu einem anderen Terminal wechseln (oder ^ Z und im selben Terminal drücken). Nun gdbsollte an diesen Prozess angehängt werden.

$ gdb -p <PID>

Dies stoppt das Skript (falls ausgeführt). Sein Zustand kann überprüft werden durch ps -f <PID>, wobei das STATFeld 'T +' ist (oder im Fall von ^ Z 'T'), was bedeutet (man ps (1))

    T Stopped, either by a job control signal or because it is being traced
    + is in the foreground process group

(gdb) call close(1)
$1 = 0

Close (1) gibt bei Erfolg Null zurück.

(gdb) call open("loop.out", 01102, 0600)
$6 = 1

Open (1) gibt bei Erfolg den neuen Dateideskriptor zurück.

Diese Öffnung ist gleich mit open(path, O_TRUNC|O_CREAT|O_RDWR, S_IRUSR|S_IWUSR). Anstelle von O_RDWR O_WRONLYkönnte angewendet werden, /usr/sbin/lsofsagt aber 'u' für alle std * -Dateihandler ( FDSpalte), das heißt O_RDWR.

Ich habe die Werte in der Header-Datei /usr/include/bits/fcntl.h überprüft.

Die Ausgabedatei könnte wie gewohnt geöffnet werden O_APPEND, nohupdies wird jedoch man open(2)aufgrund möglicher NFS-Probleme nicht empfohlen .

Wenn wir -1 als Rückgabewert erhalten, wird call perror("")die Fehlermeldung ausgegeben. Wenn wir den Fehler benötigen, verwenden Sie den Befehl p errnogdb.

Jetzt können wir die neu umgeleitete Datei überprüfen. /usr/sbin/lsof -p <PID>Drucke:

loop.sh <PID> truey    1u   REG   0,26        0 15008411 /home/truey/loop.out

Wenn wir möchten, können wir stderr in eine andere Datei umleiten, wenn wir einen anderen Dateinamen verwenden call close(2)und call open(...)erneut verwenden möchten .

Jetzt muss der Anhang bashfreigegeben werden und wir können aufhören gdb:

(gdb) detach
Detaching from program: /bin/bash, process <PID>
(gdb) q

Wenn das Skript gdbvon einem anderen Terminal aus gestoppt wurde, wird es weiter ausgeführt. Wir können zurück zum Terminal von loop.sh wechseln. Jetzt schreibt es nichts mehr auf den Bildschirm, sondern läuft und schreibt in die Datei. Wir müssen es in den Hintergrund stellen. Also drück ^Z.

^Z
[1]+  Stopped                 ./loop.sh

(Jetzt sind wir in dem Zustand, als ob ^Zam Anfang gedrückt wurde.)

Jetzt können wir den Status des Jobs überprüfen:

$ ps -f 24522
UID        PID  PPID  C STIME TTY      STAT   TIME CMD
<UID>    <PID><PPID>  0 11:16 pts/36   S      0:00 /bin/bash ./loop.sh
$ jobs
[1]+  Stopped                 ./loop.sh

Der Prozess sollte also im Hintergrund ausgeführt und vom Terminal getrennt werden. Die Zahl in der jobsAusgabe des Befehls in eckigen Klammern kennzeichnet den darin enthaltenen Job bash. Wir können in den folgenden integrierten bashBefehlen ein '%' - Zeichen vor der Jobnummer verwenden:

$ bg %1
[1]+ ./loop.sh &
$ disown -h %1
$ ps -f <PID>
UID        PID  PPID  C STIME TTY      STAT   TIME CMD
<UID>    <PID><PPID>  0 11:16 pts/36   S      0:00 /bin/bash ./loop.sh

Und jetzt können wir die Calling Bash beenden. Der Prozess läuft im Hintergrund weiter. Wenn wir die PPID beenden, wird 1 (init (1) -Prozess) und das Steuerterminal wird unbekannt.

$ ps -f <PID>
UID        PID  PPID  C STIME TTY      STAT   TIME CMD
<UID>    <PID>     1  0 11:16 ?        S      0:00 /bin/bash ./loop.sh
$ /usr/bin/lsof -p <PID>
...
loop.sh <PID> truey    0u   CHR 136,36                38 /dev/pts/36 (deleted)
loop.sh <PID> truey    1u   REG   0,26     1127 15008411 /home/truey/loop.out
loop.sh <PID> truey    2u   CHR 136,36                38 /dev/pts/36 (deleted)

KOMMENTAR

Das GDB-Zeug kann automatisiert werden, indem eine Datei (z. B. loop.gdb) erstellt wird, die die Befehle enthält, und ausgeführt werden gdb -q -x loop.gdb -p <PID>. Meine loop.gdb sieht folgendermaßen aus:

call close(1)
call open("loop.out", 01102, 0600)
# call close(2)
# call open("loop.err", 01102, 0600)
detach
quit

Oder man kann stattdessen den folgenden Liner verwenden:

gdb -q -ex 'call close(1)' -ex 'call open("loop.out", 01102, 0600)' -ex detach -ex quit -p <PID>

Ich hoffe, dies ist eine ziemlich vollständige Beschreibung der Lösung.

TrueY
quelle
Sehr informativ und funktioniert wahrscheinlich in einfachen Fällen gut. Aber seien Sie gewarnt, komplexere Fälle können kläglich scheitern. Ich hatte heute einen davon: Mein Prozess hatte einen anderen Prozess ausgelöst, der die Ausgabe (vermutlich an stderr) ausführte, aber stdout für die Kommunikation mit seinem Master angeschlossen. Das Umleiten der Master-FDs war effektiv, da das Kind stderr geerbt hatte, und das Schließen des Childs-stdout schlug fehl, wenn der Master am anderen Ende der Pipe wartete. X- | Bettern kennt Ihre Prozesse gut, bevor Sie dies versuchen.
cmaster - wieder einsetzen Monica
@cmaster Sie können überprüfen, ob ein Handle umgeleitet wird, indem lsof(der Name des Datei- Handles ist pipenicht wie /dev/pts/1) oder von ls -l /proc/<PID>/fd/<fd>(dies zeigt den Symlink des Handles). Auch Unterprozesse können immer noch keine umgeleiteten Ausgaben haben, die in eine Datei umgeleitet werden sollten.
TrueY
7

So senden Sie den laufenden Prozess an nohup ( http://en.wikipedia.org/wiki/Nohup )

nohup -p pid Bei mir hat es nicht geklappt

Dann habe ich die folgenden Befehle ausprobiert und es hat sehr gut funktioniert

  1. Führen Sie beispielsweise SOMECOMMAND aus /usr/bin/python /vol/scripts/python_scripts/retention_all_properties.py 1.

  2. Ctrl+ Zum das Programm anzuhalten (anzuhalten) und zur Shell zurückzukehren.

  3. bg um es im Hintergrund auszuführen.

  4. disown -h Damit der Prozess beim Schließen des Terminals nicht abgebrochen wird.

  5. Geben Sie ein exit, um die Shell zu verlassen, da Sie jetzt loslegen können, da der Vorgang in einem eigenen Prozess im Hintergrund ausgeführt wird, sodass er nicht an eine Shell gebunden ist.

Dieser Vorgang entspricht dem Ausführen nohup SOMECOMMAND.

minhas23
quelle
3

Auf meinem AIX-System habe ich es versucht

nohup -p  processid>

Das hat gut funktioniert. Mein Prozess wurde auch nach dem Schließen der Terminalfenster fortgesetzt. Wir haben ksh als Standard-Shell, daher funktionierten die Befehle bgund disownnicht.

Gast
quelle
2
  1. ctrl+ z - Dadurch wird der Job angehalten (nicht abgebrochen!)
  2. bg - Dadurch wird der Job in den Hintergrund gestellt und im laufenden Prozess zurückgegeben
  3. disown -a - Dadurch wird der gesamte Anhang mit dem Job abgeschnitten (sodass Sie das Terminal schließen können und es weiterhin ausgeführt wird).

Mit diesen einfachen Schritten können Sie das Terminal schließen, während der Prozess ausgeführt wird.

Es wird nicht aktiviert nohup(basierend auf meinem Verständnis Ihrer Frage, brauchen Sie es hier nicht).

Alper t. Turker
quelle
Ich denke, das Verhalten für Verleugnung -a besteht darin, die Bindung an alle Jobs zu verringern. Die stdin / stdout-Pipelines werden jedoch nicht heruntergefahren, was bedeutet, dass der Prozess weiterhin versucht, vom Terminal aus zu schreiben (/ zu lesen)
Kelthar,
-2

Dies funktionierte für mich unter Ubuntu Linux, während ich in tcshell war.

  1. CtrlZ um es anzuhalten

  2. bg im Hintergrund laufen

  3. jobs um seine Jobnummer zu bekommen

  4. nohup %n Dabei ist n die Auftragsnummer

eshaya
quelle
2
Nein, es funktioniert nicht:nohup: failed to run command '%1': No such file or directory
Dunatotatos