Linux / Befehl nohup: Einen Befehl nach dem Abmelden weiterlaufen lassen

nohup ist ein Werkzeug, das einen Befehl ausführt, während das SIGHUP-Signal ignoriert wird, das möglicherweise gesendet wird, wenn die Terminalverbindung verloren geht. Um eine Aufgabe nach dem Abmelden fortzusetzen, ist es üblich, nohup zusammen mit dem Hintergrundausführungssymbol & zu verwenden, und es wird außerdem empfohlen, die Standard-Eingabe- und Ausgabedateien explizit anzugeben.

Die praktischste Grundform ist wie folgt.

nohup ./worker.sh > worker.log 2>&1 < /dev/null &

nohup ist jedoch kein Service-Manager, der Prozesse überwacht oder neu startet. Für langfristige Dienste, die einen automatischen Start nach einem Neustart, einen Neustart bei Fehlern oder eine Protokollrotation erfordern, sind Service-Management-Tools wie systemd besser geeignet.

Was macht der Befehl nohup?

nohup führt den angegebenen Befehl aus, nachdem er so eingestellt wurde, dass das HUP-Signal ignoriert wird, SIGHUP. Beim Schließen eines Terminals oder Beenden einer SSH-Verbindung kann SIGHUP an die Shell und die zugehörigen Prozesse gesendet werden, und das Ignorieren erhöht die Wahrscheinlichkeit, dass die Aufgabe weiterläuft.

Wie in der offiziellen GNU Coreutils-Erklärung zu nohup zu sehen ist, sendet nohup selbst keinen Befehl in den Hintergrund. Um in dem aktuellen Terminal andere Arbeiten fortzusetzen, muss & separat am Ende des Befehls hinzugefügt werden.

Komponenten Was es tut Was es nicht tut
nohup Lässt den auszuführenden Befehl SIGHUP ignorieren. Wird nicht automatisch im Hintergrund ausgeführt.
& Lässt die Shell den Befehl als Hintergrundjob ausführen. Garantiert nicht, dass SIGHUP ignoriert wird.
Ausgabeumleitung Sendet Standardausgabe und Fehler an die angegebene Protokolldatei. Legt keine Protokollgrößenbeschränkungen oder automatische Löschung fest.

Grundlegende Syntax und empfohlene Ausführungsform

Grundlegende Syntax

Nach nohup schreiben Sie den auszuführenden Befehl und die Argumente in der Reihenfolge.

nohup command [arg ...]

Zum Beispiel, um backup.sh im aktuellen Verzeichnis auszuführen, geben Sie es wie folgt ein.

nohup ./backup.sh

Dieses Formular ignoriert SIGHUP, läuft aber im Vordergrund. Daher ist es schwierig, den nächsten Befehl in derselben Shell einzugeben, bis der Befehl abgeschlossen ist.

Hintergrundausführung und Protokollspeicherung

In der tatsächlichen Arbeit ist es einfacher zu verwalten, wenn Sie die Hintergrundausführung und den Protokollpfad zusammen angeben.

nohup ./backup.sh > backup.log 2>&1 < /dev/null &
  • > backup.log schreibt die Standardausgabe in eine neue Protokolldatei. Wenn dieselbe Datei existiert, überschreibt sie den vorhandenen Inhalt.
  • 2>&1 sendet den Standardfehler an denselben Ort wie die aktuelle Standardausgabe.
  • < /dev/null ersetzt die Standardeingabe durch eine Eingabequelle, die beim Lesen sofort das Dateiende meldet, sodass das Programm nicht auf eine Terminaleingabe wartet.
  • Der letzte & führt den Befehl im Hintergrund aus.

Um neue Inhalte an ein bestehendes Protokoll anzuhängen, verwenden Sie >> anstelle von >.

nohup ./backup.sh >> backup.log 2>&1 < /dev/null &

Speichern Sie die PID sofort nach der Ausführung

Direkt nach der Ausführung eines Hintergrundbefehls enthält $! die Prozess-ID (PID) des zuletzt gestarteten Hintergrundprozesses. Es ist praktisch, diesen Wert an einem sicheren Ort aufzubewahren, um später den Status zu überprüfen oder den Prozess zu beenden.

nohup ./backup.sh > backup.log 2>&1 < /dev/null &
job_pid=$!
printf '%s\n' "$job_pid" > backup.pid

Legen Sie die PID-Datei in ein Verzeichnis, in das nur der Benutzer, der den Job verwaltet, schreiben kann. Wenn alte PID-Dateien verbleiben, kann dieselbe Nummer später von einem anderen Prozess verwendet werden, daher ist es sicher, den Befehl und die Startzeit zusammen mit der Beendigung zu überprüfen.

Wie werden Standard-Eingabe und -Ausgabe gehandhabt?

Standard-Eingabe

In der GNU-Implementierung, wenn die Standard-Eingabe mit einem Terminal verbunden ist, ersetzt nohup sie durch eine nicht lesbare Eingabequelle. Dieses Verhalten reduziert Situationen, in denen das Programm anhält und auf Eingabe wartet, nachdem das Terminal verschwunden ist. Um Implementierungsunterschiede zu verringern und die Absicht zu klären, können Sie explizit < /dev/null im Befehl schreiben.

Standard-Ausgabe und nohup.out

Wenn die Standardausgabe auf das Terminal umgeleitet wird und keine separate Umleitung angegeben ist, hängt GNU nohup die Ausgabe an nohup.out im aktuellen Verzeichnis an. Wenn eine Datei im aktuellen Verzeichnis nicht erstellt werden kann, wird nohup.out im Home-Verzeichnis des Benutzers versucht, und wenn beide Orte nicht beschreibbar sind, wird der Befehl nicht ausgeführt.

Wenn mehrere Aufgaben denselben nohup.out verwenden, kann es schwierig sein zu unterscheiden, zu welcher Aufgabe die Protokolle gehören, und die Datei kann weiter wachsen. Es ist besser, für jede Aufgabe eine Protokolldatei mit einem Namen und einer Aufbewahrungsrichtlinie anzugeben.

Standardfehler

Wenn der Standardfehler an das Terminal weitergeleitet wird, sendet GNU nohup ihn im Allgemeinen an dasselbe Ziel wie die Standardausgabe. Je nach Shell, Betriebssystem oder zuvor angewendeten Umleitungen können die Ergebnisse jedoch von den Lesern missverstanden werden, daher ist es sicherer, Ihre Absicht ausdrücklich mit 2>&1 anzugeben. Die Reihenfolge der Ein-/Ausgabeverbindungen in der Shell beeinflusst das Ergebnis, und die detaillierten Prinzipien finden Sie in der GNU Coreutils I/O-Umleitungsdokumentation.

Überprüfen des Ausführungsstatus und der Protokolle

Überprüfen von Prozessen mit gespeichertem PID

Wenn Sie die PID direkt nach der Ausführung gespeichert haben, können Sie sie direkt an ps übergeben, um ihren Status zu überprüfen.

job_pid=$(cat backup.pid)
ps -p "$job_pid" -o pid,ppid,stat,etime,cmd

PID ist die Prozess-ID, PPID ist die übergeordnete Prozess-ID, STAT ist der Status und ELAPSED ist die Ausführungszeit. Gehen Sie nicht davon aus, dass es sich um die gewünschte Aufgabe handelt, nur weil die PID existiert; überprüfen Sie auch die Spalte Befehl am Ende.

Einen Prozess anhand des Namens finden

Wenn die PID nicht gespeichert wurde, können Sie die Befehlszeile mit pgrep durchsuchen.

pgrep -af 'backup.sh'

Da auch andere Prozesse mit demselben String gefunden werden können, sollten Sie die gesamte Befehlszeile des Ergebnisses überprüfen. Wenn Sie die Ausgabe von ps einfach in grep pipen, wird oft der Suchbefehl selbst angezeigt und ist daher nicht für die Automatisierung geeignet.

Protokolle in Echtzeit überprüfen

Mit tail -f können Sie kontinuierlich Ergänzungen am Ende einer Datei anzeigen.

tail -f backup.log

Um die Protokollüberwachung zu beenden, drücken Sie Ctrl+C. Dies beendet nur tail und stoppt nicht die ursprüngliche Aufgabe, die das Protokoll schreibt. Weitere Details zum Festlegen der Anzahl der Zeilen und zum Verfolgen von Dateien finden Sie unter Wie man den Tail-Befehl verwendet.

Beenden eines mit nohup gestarteten Prozesses

Zuerst eine normale Beendigung anfordern

Nach Überprüfung der Ziel-PID und des Befehls sendet das Ausführen von kill im Wesentlichen das SIGTERM-Signal. Wenn das Programm eine Beendigungshandhabung implementiert hat, erhält es die Möglichkeit, Dateien zu schließen und seinen Zustand aufzuräumen.

job_pid=$(cat backup.pid)
ps -p "$job_pid" -o pid,ppid,stat,etime,cmd
kill "$job_pid"

Überprüfen, ob es beendet wurde

Warten Sie einen Moment und prüfen Sie dann erneut dieselbe PID.

ps -p "$job_pid" -o pid,stat,etime,cmd

Wenn ein Shell-Skript mehrere Kindprozesse erstellt hat, kann das Beenden nur eines Elternprozesses die Kinder laufen lassen. Überprüfen Sie zuerst den Prozessbaum und die Prozessgruppen, und wenn das von Ihnen verwendete Programm einen offiziellen Beendigungsbefehl bereitstellt, hat die Verwendung dieses Befehls Vorrang.

Verwenden Sie die Zwangsbeendigung nur als letzte Möglichkeit

Wenn Sie sofort eine erzwungene Beendigung durchführen, nur weil es nicht auf SIGTERM reagiert, können Daten möglicherweise nicht gespeichert werden oder temporäre Dateien werden nicht bereinigt. Stellen Sie sicher, dass Ursache und Ziel korrekt sind, und verwenden Sie SIGKILL nur als letzten Ausweg.

kill -KILL "$job_pid"

Ausführen von Pipelines und zusammengesetzten Befehlen

Gruppierung in einen einzelnen Shell-Befehl

Sie können einen Befehlsstring an die Shell übergeben, um eine Pipeline, mehrere Umleitungen und bedingte Operatoren als einzelne Aufgabe auszuführen.

nohup sh -c 'producer | consumer' > pipeline.log 2>&1 < /dev/null &

Zu diesem Zeitpunkt wird die Pipeline innerhalb der Anführungszeichen von einer neuen Shell interpretiert. Wenn Sie externe Eingaben ohne Validierung in den Befehlsstring einfügen, besteht das Risiko einer Befehlsinjektion. Fügen Sie daher keine nicht vertrauenswürdigen Werte direkt ein. Sie können auch How to Use Bash Command Connection Operators für die Ausführungsbeziehung von Shell-Operatoren konsultieren.

Wenn Protokolle nicht sofort sichtbar sind

Wenn der Prozess läuft, die Protokolle jedoch verspätet erscheinen, könnte die Ursache die Ausgabepufferung des Programms sein und nicht nohup. Überprüfen Sie zunächst die Einstellungen zur Ausgabepufferung des Programms selbst. In GNU-basierten Umgebungen können Sie, wenn das Programm und die Ausgabemethode kompatibel sind, Zeilenpufferung mit stdbuf anfordern.

nohup stdbuf -oL -eL ./worker > worker.log 2>&1 < /dev/null &

stdbuf funktioniert nicht für alle Programme. Wenn das Programm seinen eigenen Puffer zurücksetzt oder eine spezielle Ein-/Ausgabemethode verwendet, kann es möglicherweise nicht angewendet werden.

Grenzen von nohup und Kriterien zur Auswahl anderer Werkzeuge

Funktionen, die von nohup nicht bereitgestellt werden

nohup ist ein einfaches Ausführungswerkzeug, das die Handhabung eines Signals ändert. Die folgenden Funktionen werden nicht bereitgestellt.

  • Automatischer Start nach Systemneustart
  • Automatischer Neustart, wenn der Prozess abnormal beendet wird
  • Verwaltung der Startreihenfolge abhängiger Dienste
  • Ressourcenbegrenzung und Statusüberwachung wie CPU und Speicher
  • Begrenzung der Protokolldateigröße, Kompression, Aufbewahrung und Löschung
  • Erhaltung von interaktiven Terminal-Sitzungen

Unterschiede zu systemd, tmux, screen

Werkzeuge Geeignete Situationen Funktionen
nohup Temporäres Ausführen von nicht-interaktiven Batch-Aufgaben Einfach, verfügt jedoch nicht über Überwachungs-, Neustart- oder Funktionen zur Protokollrotation.
systemd Dienste, die kontinuierlich auf dem Server laufen Sie können die Bootintegration, Neustart-Richtlinien, Abhängigkeiten konfigurieren und Protokolle sowie Ressourcen verwalten.
tmux/screen Interaktive Aufgaben, die später wieder verbunden werden müssen Sie können virtuelle Terminalsitzungen trennen und wieder verbinden.
Aufgabenplaner Aufgaben, die zu einem festen Zeitpunkt oder Intervall ausgeführt werden Verwalten Sie die Ausführungszeiten und Historie mit cron oder einer dedizierten Job-Warteschlange.

Unterschied zu disown

disown ist eine in einigen Shells wie Bash eingebauter Befehl, die einen bereits gestarteten Job aus der Jobliste der Shell entfernt oder die Handhabung des Hangup-Signals ändert. Im Gegensatz dazu ist nohup ein externes Programm, das bewirkt, dass ein Befehl SIGHUP ab dem Moment seines Starts ignoriert. Da die Optionen und das Verhalten von disown je nach Shell variieren, sollten Sie die Dokumentation der aktuellen Shell für portierbare Skripte prüfen.

Checkliste für sichere Ausführung

  • Pfad: Geben Sie Skripte, Konfigurationsdateien und Protokolldateien wann immer möglich mit absolutem Pfad an. Dies stellt sicher, dass dieselben Dateien verwendet werden, auch wenn sich der Anmeldeort ändert.
  • Berechtigungen: Überprüfen Sie, ob Passwörter, Tokens oder persönliche Informationen in Protokollen verbleiben könnten, und beschränken Sie die Datei-Berechtigungen.
  • Größe: Konfigurieren Sie logrotate oder die eigene Protokollaufbewahrungsrichtlinie des Programms, um zu verhindern, dass Protokolle kontinuierlich wachsen.
  • Doppelte Ausführung: Überprüfen Sie, ob es sicher ist, dieselbe Aufgabe gleichzeitig mehrfach auszuführen. Falls erforderlich, verwenden Sie Sperrdateien oder die Einzel-Ausführungsfunktion des Programms.
  • Umgebung: Bei nicht-interaktiver Ausführung können sich das Arbeitsverzeichnis, PATH, die Gebietsschemaeinstellungen und Umgebungsvariablen von der Login-Shell unterscheiden, daher geben Sie die notwendigen Werte an.
  • Empfindliche Argumente: Wenn Sie Passwörter oder Tokens als Befehlszeilenargumente übergeben, können andere Benutzer diese in der Prozessliste sehen. Verwenden Sie Anmeldedateien oder von dem Programm unterstützte Methoden zur geheimen Speicherung.
  • Beendigungsverfahren: Notieren Sie die PID sofort nach der Ausführung und bereiten Sie sowohl die normale Beendigungsmethode als auch die Schritte zur Überprüfung verbleibender Kindprozesse vor.

Häufig gestellte Fragen

Wird ein nohup-Job definitiv bestehen bleiben, wenn ich das SSH-Fenster schließe?

Befehle, die mit nohup beginnen, ignorieren SIGHUP, aber dies garantiert nicht absolut eine Job-Persistenz in allen Umgebungen. Wenn ein Programm separate Kindprozesse erstellt, während es Signal-Einstellungen ändert, oder das Terminalgerät weiterhin verwendet, kann das Ergebnis unterschiedlich sein. Trennen Sie sowohl die Standardeingabe als auch die Standardausgabe vom Terminal, und für wichtige, lang laufende Aufgaben ist es sicherer, einen Dienstmanager zu verwenden.

Wie kann ich verhindern, dass die Datei nohup.out erstellt wird?

Sie können die Standardausgabe und den Standardfehler direkt festlegen. Nur Aufgaben, die überhaupt keine Protokollierung erfordern, können an /dev/null gesendet werden. Da jedoch auch diagnostische Informationen verloren gehen, wird normalerweise empfohlen, separate Protokolldateien für betriebliche Aufgaben zu verwenden.

nohup ./worker > /dev/null 2>&1 < /dev/null &

Warum erscheinen Jobs nicht in jobs?

jobs zeigt nur Aufgaben an, die von der aktuellen Shell verwaltet werden. Wenn Sie sich abmelden und eine neue Shell verbinden, wird die Jobliste der vorherigen Shell nicht übernommen, sodass sie in jobs nicht erscheint. Verwenden Sie die gespeicherte PID und ps oder verwenden Sie die Statusprüffunktion von Dienstverwaltungswerkzeugen.

Was bedeutet der Exit-Code von nohup?

In der GNU-Implementierung werden für Fehler in nohup selbst, Fälle, in denen der Befehl nicht gefunden werden kann, oder Fälle, in denen der Befehl nicht ausgeführt werden kann, separate Exit-Codes verwendet. Wenn der Befehl erfolgreich startet, gibt er den Exit-Status dieses Befehls zurück. Der genaue Wert kann durch die Implementierung und die POSIXLY_CORRECT-Einstellung beeinflusst werden, daher sollten für die Automatisierung nohup --help und die offizielle Dokumentation des Systems überprüft werden. Beachten Sie auch, dass nach dem Start im Hintergrund und dem Verlassen der Shell $? in dieser Shell nicht einfach gelesen werden kann, um das endgültige Ergebnis der Aufgabe zu erhalten.

Zusammenfassung

nohup führt einen Befehl aus, sodass er SIGHUP ignoriert, was beim Abmelden oder Schließen des Terminals auftreten kann. Typische nicht-interaktive Aufgaben verwenden nohup zusammen mit & und expliziter Standard-Eingabe-/Ausgabeumleitung, und das sofortige Speichern der PID nach der Ausführung erleichtert die Verwaltung.

Wenn die Aufgabe auch nach einem Neustart starten oder eine automatische Wiederherstellung im Fehlerfall erfordern muss, wählen Sie einen Dienstmanager wie systemd anstelle von nohup. Um sich einen Überblick über andere Grundwerkzeuge zu verschaffen, können Sie auf die Liste der häufig verwendeten Befehle in Linux verweisen.