nohup, disown und setsid in Bash im Detail verstehen
AI generated
$_
#!/
Bash · Prozesse · Deployment
nohup, disown und setsid in Bash
SIGHUP verstehen und Hintergrunddienste sauber vom Terminal lösen

nohup ignoriert das Signal SIGHUP, disown entfernt einen Job nachträglich aus der Job-Tabelle der Shell, und setsid startet eine komplett neue Session ohne kontrollierendes Terminal. Wer den Unterschied kennt, wählt für jeden Hintergrunddienst in einem Deployment-Skript das jeweils passende, robusteste Werkzeug.

16 Min. Lesezeit nohup · disown · setsid SIGHUP · Sessions · Daemonisierung

1. Das Grundproblem: SIGHUP und die Bindung an das kontrollierende Terminal

Jeder interaktiv gestartete Prozess ist normalerweise an ein kontrollierendes Terminal gebunden, über eine Session, die die Shell beim Login oder beim Öffnen eines Terminal-Fensters aufbaut. Schließt der Benutzer dieses Terminal oder trennt sich eine SSH-Verbindung, sendet der Kernel an alle Prozesse dieser Session das Signal SIGHUP, dessen Standardverhalten ohne expliziten Handler die sofortige Beendigung des Prozesses ist.

Für ein kurzes, interaktives Kommando ist dieses Verhalten meist erwünscht, für einen im Hintergrund gestarteten Deployment-Prozess, der auch nach dem Schließen der SSH-Sitzung weiterlaufen soll, ist es dagegen ein echtes Problem. Genau hier setzen nohup, disown und setsid an, jedes mit einem unterschiedlichen Mechanismus, um einen Prozess vor diesem Signal zu schützen oder ihn erst gar nicht an das Terminal zu binden.

2. nohup im Detail: wie es SIGHUP gezielt abfängt

nohup startet ein Kommando mit einer expliziten Ignorierung des Signals SIGHUP, sodass der Kernel das Signal zwar weiterhin an den Prozess sendet, sobald das Terminal getrennt wird, der Prozess es aber laut seiner Signal-Maske ignoriert und deshalb nicht beendet wird. Standardmäßig leitet nohup zusätzlich stdout und stderr in eine Datei namens nohup.out um, weil ein vom Terminal getrennter Prozess sonst versuchen würde, in ein nicht mehr existierendes Terminal zu schreiben, was zu einem weiteren Signal führen kann.

nohup ändert dabei ausdrücklich nichts an der Prozessgruppen- oder Session-Zugehörigkeit des gestarteten Prozesses, der Prozess bleibt technisch Teil derselben Session wie die startende Shell. Läuft die Shell selbst noch, etwa weil sie in einem tmux-Fenster steckt, bleibt der mit nohup gestartete Prozess trotzdem Kind dieser Shell und wird beendet, falls die Shell selbst mit SIGKILL beendet wird, ein Signal, das sich grundsätzlich nicht ignorieren lässt.


nohup ./long-running-deploy.sh > deploy.log 2>&1 &
deploy_pid=$!
echo "Laeuft als PID $deploy_pid, SIGHUP wird ignoriert"

3. disown: einen bereits laufenden Job aus der Job-Tabelle der Shell entfernen

disown entfernt einen im Hintergrund laufenden Job aus der internen Job-Tabelle der aktuellen Shell, ohne den Prozess selbst zu beeinflussen. Der wichtigste Effekt: Ohne Eintrag in der Job-Tabelle sendet die Shell beim eigenen Beenden kein SIGHUP mehr an diesen Prozess, weil sie ihn schlicht nicht mehr als eigenen Job kennt, während sie ohne disown standardmäßig SIGHUP an alle noch laufenden Hintergrundjobs weiterreicht.

Der entscheidende Unterschied zu nohup: disown wirkt erst nachträglich auf einen bereits gestarteten Hintergrundprozess (mit & gestartet), während nohup schon beim Start eingesetzt werden muss. Wer vergessen hat, einen langlaufenden Prozess mit nohup zu starten, kann disown -h %1 nutzen, um genau diesen Effekt nachträglich zu erreichen, ohne den Prozess neu starten zu müssen.


./long-running-deploy.sh &
deploy_pid=$!

# Realized too late that nohup was forgotten - fix it after the fact
disown -h %1
echo "Job aus der Job-Tabelle entfernt, PID $deploy_pid ueberlebt SIGHUP"

4. setsid: eine neue Sitzung ohne kontrollierendes Terminal starten

setsid startet ein Kommando in einer komplett neuen Session, in der der neue Prozess automatisch zum Session-Leader wird und von vornherein kein kontrollierendes Terminal besitzt. Das ist ein grundlegend anderer Mechanismus als nohup: nohup lässt den Prozess in derselben Session, ignoriert nur das Signal, während setsid den Prozess von der Session der startenden Shell komplett löst, noch bevor überhaupt ein SIGHUP relevant werden könnte.

Weil ein Prozess ohne kontrollierendes Terminal grundsätzlich kein SIGHUP durch eine Terminaltrennung mehr empfangen kann, es gibt schließlich kein Terminal mehr, das dieses Signal auslösen würde, ist setsid der robusteste der drei Mechanismen für echte Hintergrunddienste. Der Nachteil: Ein mit setsid gestarteter Prozess kann nicht mehr über die normale Job-Kontrolle der Shell angesprochen werden, weil er formal keiner interaktiven Shell-Session mehr angehört.


setsid ./deploy-daemon.sh > deploy.log 2>&1 < /dev/null &
echo "Neue Session gestartet, kein kontrollierendes Terminal"

5. Unterschied zwischen vom Terminal getrennt und ohne kontrollierendes Terminal

nohup und disown lösen ein anderes Problem als setsid, auch wenn alle drei häufig im selben Atemzug genannt werden. nohup und disown sorgen dafür, dass ein Prozess ein SIGHUP übersteht oder es gar nicht erst empfängt, ändern aber nichts daran, dass der Prozess weiterhin formal Mitglied der ursprünglichen Session ist, mit demselben kontrollierenden Terminal, falls dieses noch existiert.

setsid dagegen entfernt das kontrollierende Terminal von vornherein, unabhängig davon, ob es später getrennt wird oder nicht. Dieser Unterschied wird relevant, sobald ein Prozess selbst versucht, mit dem Terminal zu interagieren, etwa eine Passwortabfrage auf stdin auszugeben: Ein Prozess ohne kontrollierendes Terminal scheitert an solchen Interaktionen von Anfang an, ein nur mit nohup geschützter Prozess dagegen so lange nicht, wie sein Terminal tatsächlich existiert.

6. Die Kombination nohup, & und disown in der Praxis

In den meisten Deployment-Skripten reicht die Kombination aus nohup beim Start und dem Hintergrund-Operator & völlig aus, um einen Prozess sicher über das Ende einer SSH-Sitzung hinweg laufen zu lassen. disown wird in der Praxis vor allem dann gebraucht, wenn nohup aus irgendeinem Grund vergessen wurde oder wenn ein interaktiv gestarteter Job nachträglich, ohne Neustart, von der aktuellen Shell abgekoppelt werden soll.

Ein robustes Muster für ein Deployment-Skript kombiniert deshalb nohup für den SIGHUP-Schutz mit einer expliziten Umleitung von stdin, stdout und stderr, damit der Prozess unter keinen Umständen versucht, mit dem möglicherweise schon geschlossenen Terminal zu interagieren, selbst wenn nohup allein das SIGHUP-Signal bereits abfängt.


nohup ./deploy-worker.sh < /dev/null > deploy.log 2>&1 &
worker_pid=$!
disown "$worker_pid" 2>/dev/null || true
echo "Worker $worker_pid laeuft unabhaengig von dieser Sitzung"

7. Wann setsid wirklich nötig ist: echte Daemonisierung

Für die meisten Deployment-Skripte, die einen einmaligen Hintergrundprozess starten, reichen nohup und & aus, weil moderne Deployment-Umgebungen ohnehin selten Prozesse dauerhaft an eine interaktive SSH-Sitzung binden wollen. setsid wird dagegen unverzichtbar, sobald ein Prozess echte Daemon-Eigenschaften braucht: keinerlei Bindung an ein Terminal, keine versehentliche Job-Kontrolle durch eine Shell, und eine eigene, unabhängige Session, die ihn zum Beispiel vor SIGHUP-Ketten durch Terminal-Multiplexer wie tmux vollständig abschirmt.

In produktiven systemd-basierten Umgebungen übernimmt systemd selbst bereits die Rolle von setsid für jeden Dienst, den es startet, weshalb explizites setsid in solchen Skripten meist überflüssig ist. Relevant bleibt setsid vor allem für Legacy-Deployment-Skripte ohne systemd-Integration oder für Fälle, in denen ein Prozess bewusst aus einem interaktiven Cron- oder CI-Kontext heraus vollständig von der aufrufenden Session gelöst werden muss.

8. Deployment-Skripte: welches Werkzeug für welchen Hintergrunddienst passt

Für kurzlebige Hintergrundprozesse innerhalb eines interaktiven Deployment-Skripts, die den Rest des Skriptlaufs überdauern sollen, reicht in der Regel nohup in Kombination mit &, ergänzt um eine explizite Umleitung aller Standard-Streams. Für nachträgliches Abkoppeln eines bereits laufenden Jobs, den man vergessen hat mit nohup zu schützen, ist disown das richtige, gezielte Werkzeug, ohne den Prozess neu starten zu müssen.

Für echte, langlebige Hintergrunddienste, die dauerhaft und unabhängig von jeder interaktiven Sitzung laufen sollen, ist eine systemd-Unit-Datei die eigentlich richtige Lösung, weil sie Neustarts, Logging und Ressourcenlimits einheitlich regelt. setsid bleibt das passende Werkzeug für den Übergangsfall, in dem echte Daemonisierung außerhalb einer systemd-Umgebung nötig ist, etwa in minimalen Container-Basisimages ohne eigenen Init-Prozess.

9. Fallstricke: Stream-Umleitung und doppeltes Forking

Der häufigste Fehler bei allen drei Werkzeugen ist, stdin nicht explizit umzuleiten. Ein Hintergrundprozess, der versucht, von stdin zu lesen, während das ursprüngliche Terminal längst geschlossen ist, blockiert unter Umständen unendlich oder erhält beim Lesen ein Fehlersignal, je nachdem, wie der jeweilige Prozess mit einem geschlossenen Deskriptor umgeht, weshalb < /dev/null in produktiven Skripten praktisch immer dazugehört.

Ein zweiter, subtilerer Fallstrick betrifft doppeltes Forking bei echter Daemonisierung: Ein mit setsid gestarteter Prozess ist zwar Session-Leader ohne Terminal, kann aber unter bestimmten Umständen selbst wieder ein Terminal öffnen und damit erneut ein kontrollierendes Terminal erhalten. Klassische Unix-Daemons vermeiden das durch einen zweiten fork() nach setsid, sodass der eigentliche Daemon-Prozess selbst kein Session-Leader mehr ist und deshalb gar kein Terminal mehr erhalten kann, ein Detail, das setsid allein nicht abdeckt.

Werkzeug Zeitpunkt der Anwendung Löst SIGHUP Trennt Terminal komplett
nohup Beim Start des Prozesses Ja, durch Ignorieren Nein, Session bleibt bestehen
disown Nach dem Start, nachträglich Ja, durch Entfernen aus Job-Tabelle Nein, Session bleibt bestehen
setsid Beim Start, neue Session Ja, indirekt Ja, von Anfang an kein Terminal
nohup + disown Start und nachträglich kombiniert Ja, doppelt abgesichert Nein, aber praktisch robust

Mironsoft

Shell-Automatisierung, DevOps-Tooling und Deployment-Infrastruktur

Shell-Skripte, die in der Produktion zuverlässig laufen?

Wir analysieren bestehende Bash-Skripte, erkennen fragile Muster und ersetzen sie durch robuste Bash-Patterns: mit vollständiger Fehlerbehandlung, Logging und sicherer Parallelisierung für euren Deployment-Stack.

Code-Review

ShellCheck-Analyse und manuelle Prüfung auf kritische Bash-Pattern-Verstöße.

Refactoring

Fehlerbehandlung, Logging und sichere Dateioperationen nachrüsten.

CI-Integration

ShellCheck und BATS in Pipelines integrieren und Regressionstests aufbauen.

10. Zusammenfassung

nohup, disown und setsid: Das Wichtigste auf einen Blick

SIGHUP-Ursache

Terminaltrennung sendet SIGHUP an alle Prozesse der Session, Standardverhalten ist sofortige Beendigung.

nohup

Ignoriert SIGHUP gezielt beim Start des Prozesses, lässt die Session-Zugehörigkeit aber unverändert.

disown

Entfernt einen bereits laufenden Job nachträglich aus der Job-Tabelle, ohne den Prozess neu zu starten.

setsid

Startet eine komplett neue Session ohne kontrollierendes Terminal, robustester Mechanismus für echte Daemons.

11. FAQ: nohup, disown und setsid: Das Wichtigste auf einen Blick

1Was genau löst das Signal SIGHUP aus?
Das Schließen eines Terminals oder das Trennen einer SSH-Verbindung sendet SIGHUP an alle Prozesse der zugehörigen Session. Ohne expliziten Handler führt das Signal standardmäßig zur sofortigen Beendigung des Prozesses.
2Was macht nohup genau?
nohup startet ein Kommando mit ignoriertem SIGHUP-Signal und leitet stdout/stderr standardmäßig in nohup.out um. Die Session-Zugehörigkeit des Prozesses bleibt dabei unverändert.
3Wann brauche ich disown statt nohup?
Wenn ein Prozess bereits läuft und vergessen wurde, ihn mit nohup zu starten. disown entfernt ihn nachträglich aus der Job-Tabelle der Shell, ohne einen Neustart zu erfordern.
4Was ist der Unterschied zwischen nohup und setsid?
nohup ignoriert nur das SIGHUP-Signal, lässt den Prozess aber in derselben Session. setsid startet eine komplett neue Session ohne kontrollierendes Terminal von Anfang an.
5Warum blockiert mein Hintergrundprozess manchmal unerwartet?
Meist weil stdin nicht umgeleitet wurde und der Prozess versucht, von einem nicht mehr existierenden Terminal zu lesen. < /dev/null sollte deshalb bei jedem Hintergrundprozess gesetzt werden.
6Kann ich einen mit setsid gestarteten Prozess noch mit jobs oder fg ansprechen?
Nein, ein mit setsid gestarteter Prozess gehört formal keiner interaktiven Shell-Session mehr an und ist deshalb über die normale Job-Kontrolle nicht mehr erreichbar.
7Brauche ich setsid, wenn mein Dienst über systemd gestartet wird?
In der Regel nicht, weil systemd diese Rolle für jeden von ihm gestarteten Dienst bereits selbst übernimmt. setsid bleibt vor allem für Legacy-Skripte ohne systemd-Integration relevant.
8Was ist doppeltes Forking und wozu dient es?
Ein zweiter fork() nach setsid sorgt dafür, dass der eigentliche Daemon-Prozess kein Session-Leader mehr ist und deshalb technisch gar kein kontrollierendes Terminal mehr erhalten kann, selbst wenn er es versuchen würde.
9Kann ein Prozess SIGKILL mit nohup überleben?
Nein, SIGKILL lässt sich grundsätzlich nicht ignorieren oder abfangen, weder mit nohup noch mit einem anderen Mechanismus. Nur SIGHUP und andere handhabbare Signale lassen sich auf diese Weise ignorieren.
10Welches Werkzeug ist für einen produktiven Hintergrunddienst am robustesten?
Eine systemd-Unit-Datei ist die eigentlich richtige Lösung für dauerhafte Dienste. Außerhalb von systemd ist setsid der robusteste der drei Mechanismen, weil er von vornherein kein Terminal bindet.