Job-Control ist die Fähigkeit der Bash, mehrere Prozesse gleichzeitig im selben Terminal zu verwalten — pausieren, in den Hintergrund schicken, wieder hervorholen. Wer &, jobs, fg, bg und Ctrl + Z beherrscht, braucht für viele Aufgaben kein zweites Terminalfenster mehr. Das Konzept stammt aus den frühen Unix-Tagen und ist bis heute ein zentrales Werkzeug für effizientes Arbeiten auf der Kommandozeile.
Was Job-Control ist
Die Bash kann mehrere Prozesse gleichzeitig im selben Terminal verwalten. Ein Prozess kann entweder im Foreground laufen — dann blockiert er die Eingabe und bekommt Tastatur-Input direkt zugestellt — oder im Background, wo er ohne Interaktion weiterarbeitet und das Terminal frei lässt. Die Steuerung dieser Modi nennt man Job-Control.
Wichtig zu unterscheiden: Ein Job ist nicht dasselbe wie ein Prozess. Ein Job ist ein Bash-internes Konzept und kann aus einer ganzen Pipeline mehrerer Prozesse bestehen. Startest du cat log | grep ERROR | wc -l &, ist das ein einziger Job mit drei Prozessen. Die Bash verwaltet Jobs über fortlaufende Job-Nummern (%1, %2, …), der Kernel kennt diese Nummern nicht — er sieht nur die einzelnen Prozesse und ihre Process Group ID (PGID).
Job-Control ist standardmäßig in jeder interaktiven Bash-Sitzung aktiv. In nicht-interaktiven Skripten ist sie meistens deaktiviert; mit set -m lässt sie sich dort einschalten.
Im Hintergrund starten — &
Hängst du an einen Befehl ein & an, startet die Bash ihn im Background. Das Terminal bleibt sofort frei, du kannst weiterarbeiten. Die Bash gibt dabei die Job-Nummer und die PID aus.
make &[1] 12453Die Ausgabe [1] 12453 heißt: Job-Nummer 1, PID 12453. Klassischer Einsatz ist alles, was lange läuft und keine Tastatureingabe erwartet — Builds, Konvertierungen, Downloads, lokale Server. Sobald der Background-Job endet, meldet die Bash das beim nächsten Prompt mit [1]+ Done make.
Pause und Resume
Ein laufender Foreground-Prozess lässt sich mit Ctrl + Z pausieren. Die Bash schickt dem Prozess das Signal SIGTSTP (Terminal Stop), der Prozess geht in den Zustand T (Stopped) und du bekommst sofort den Prompt zurück. Der Job ist nicht beendet, sondern eingefroren — sein Speicher, seine offenen Dateien und sein Zustand bleiben erhalten.
Aus diesem Pausenzustand gibt es zwei Wege zurück:
bgsetzt den Job im Background fort (er läuft weiter, aber das Terminal bleibt frei)fgholt ihn als Foreground-Job zurück (du landest wieder in der Anwendung)
Im Hintergrund weckt die Bash den Job mit dem Signal SIGCONT. Mehr zu Signalen und ihrer Wirkung im Artikel Signale unter Linux.
jobs
Der Befehl jobs listet alle Jobs der aktuellen Shell mit ihrem Status auf — typischerweise Running, Stopped oder Done.
jobs[1] Running make &
[2]- Stopped vim notes.md
[3]+ Running npm run dev &Das + markiert den current job, das - den previous job. Diese Kennzeichnungen sind keine Spielerei: Sie sind die Grundlage der Job-Specs, mit denen du Jobs gezielt ansprechen kannst.
| Job-Spec | Bedeutung |
|---|---|
%1, %2, … | Job mit der angegebenen Nummer |
%% oder %+ | Current Job (zuletzt im Foreground oder per bg/fg angesprochen) |
%- | Previous Job (der vorherige Current Job) |
%vim | Job, dessen Befehlszeile mit dem Namen beginnt |
%?error | Job, dessen Befehlszeile den String enthält |
Mit jobs -l werden zusätzlich die PIDs angezeigt, mit jobs -p nur die PIDs — praktisch, wenn du sie an kill oder ein Skript weitergeben willst.
fg und bg
fg holt einen Job in den Foreground, bg setzt einen gestoppten Job im Background fort. Beide akzeptieren eine Job-Spec; ohne Argument wirken sie auf den Current Job (%%).
fg %1 # Job 1 in den Vordergrund holen
bg %2 # Job 2 im Hintergrund fortsetzen
fg # Current Job zurückholen
fg %vim # Job zurückholen, der mit "vim" beginntfg ist der schnellste Weg zurück in einen pausierten Editor: einmal Ctrl + Z, etwas erledigen, dann fg und du bist wieder mittendrin. bg braucht man, wenn ein Befehl versehentlich ohne & gestartet wurde — Ctrl + Z plus bg ist die Rettung.
Job vs. Prozess vs. PGID
Drei Begriffe, die leicht verwechselt werden:
| Begriff | Wer kennt es? | Was ist es? |
|---|---|---|
| Job | nur die Bash | interne Nummer (%1) für eine Pipeline oder einen einzelnen Befehl |
| Prozess | der Kernel | jede laufende Programminstanz mit eigener PID |
| PGID | der Kernel | Process Group ID — fasst alle Prozesse eines Jobs zusammen |
Wenn du cat log | grep ERROR | wc -l & startest, entstehen drei Prozesse mit drei PIDs, aber alle drei haben dieselbe PGID — die PID des ersten Prozesses (cat). Die Bash merkt sich diese PGID intern und ordnet ihr die Job-Nummer zu.
Daraus folgt ein praktischer Trick: Mit kill -- -PGID (das führende Minus markiert eine Prozessgruppe) erlegst du den ganzen Job-Verbund mit einem Schlag. Details und weitere Signal-Optionen im Artikel kill und Prozesse beenden.
Praxis-Patterns
Die folgenden Muster decken die meisten Alltagsfälle ab. Jeder Block kommt mit einer kurzen Erklärung, wann und warum er nützlich ist.
Build im Hintergrund starten — der klassische Einsatz von &. Während der Build läuft, bleibt das Terminal nutzbar; der Exit-Status wird beim nächsten Prompt gemeldet.
make &Editor pausieren, Shell-Befehl, zurückkehren — der häufigste Job-Control-Workflow überhaupt. Statt ein zweites Terminal zu öffnen, parkst du den Editor kurz und kommst danach genau dort zurück, wo du warst.
vim README.md
# Ctrl + Z pausiert vim
git status
fgMehrere Builds parallel und auf alle warten — wait ohne Argument blockiert, bis alle Background-Jobs fertig sind. So lassen sich unabhängige Schritte sauber parallelisieren.
make backend &
make frontend &
wait
echo "alle Builds fertig"Job per Name fortsetzen — wenn mehrere Jobs laufen, ist der Name oft eindeutiger als die Nummer.
fg %vimJob killen — kill versteht Job-Specs direkt, du musst keine PID nachschlagen.
kill %1Output beim Background-Start umleiten — ohne Umleitung schreiben Background-Jobs weiter ins Terminal und stören jede Eingabe. Mit > log 2>&1 & landet stdout und stderr in einer Datei.
long-running-task > task.log 2>&1 &Stolperfallen
Ein einzelnes & ist nicht &&
cmd1 & cmd2 startet cmd1 im Hintergrund und führt sofort cmd2 aus — egal ob cmd1 erfolgreich war. cmd1 && cmd2 dagegen wartet auf cmd1 und startet cmd2 nur, wenn der Exit-Code 0 war. Die Verwechslung ist ein Klassiker; ein vergessenes zweites & kann ganze Pipelines durcheinanderbringen.
Background-Jobs schreiben weiter ins Terminal
Wenn du einen Befehl mit & startest, läuft seine Ausgabe trotzdem weiter ins aktuelle Terminal — mitten in deine nächste Eingabe. Lösung ist immer dieselbe: stdout und stderr umleiten, also cmd > log 2>&1 &. Wer das routinemäßig macht, hat sauberere Sessions und kann die Logs später bequem nachlesen.
Terminal zu — Jobs sterben
Schließt du das Terminal-Fenster oder beendest die Login-Sitzung, schickt der Kernel ein SIGHUP an alle Prozesse der Session. Background-Jobs sterben dabei mit. Wer länger laufende Aufgaben terminalunabhängig braucht, nutzt nohup, disown oder einen Terminal-Multiplexer — siehe nohup und disown.
set -m schaltet Job-Control ein
In nicht-interaktiven Bash-Skripten ist Job-Control standardmäßig aus. Befehle wie fg und bg funktionieren dort nicht, und Background-Jobs laufen ohne eigene Process Group. Mit set -m lässt sich Job-Control auch in Skripten aktivieren — nötig zum Beispiel, wenn man Subshells gezielt mit kill -- -PGID beerdigen will.
wait ohne Argument wartet auf alle
wait allein blockiert die Shell, bis alle Background-Jobs fertig sind. Mit wait %1 wartest du nur auf einen bestimmten Job, mit wait $! auf den zuletzt gestarteten. Praktisch, wenn ein Skript mehrere Tasks parallel startet und am Ende ihre Exit-Codes auswerten soll.
Pipeline mit & ist EIN Job
cmd1 | cmd2 | cmd3 & ergibt einen einzigen Job mit drei Prozessen, nicht drei Jobs. Die Bash gibt nur eine Job-Nummer aus, und kill %1 beendet alle drei Prozesse über ihre gemeinsame Process Group. Wer einzelne Glieder einer Pipeline gezielt beenden will, muss mit PIDs arbeiten — die Job-Spec greift immer den ganzen Verbund.
Tab schliessen sendet SIGHUP
Tab-Close, Window-Close oder das Beenden der SSH-Verbindung lösen alle dasselbe Verhalten aus: Die kontrollierende Shell beendet sich, und der Kernel schickt allen Mitgliedern der Session ein SIGHUP. Nur Jobs, die per disown aus der Job-Liste entfernt oder per nohup gegen SIGHUP gepanzert wurden, überleben das.
disown loest Jobs vom Terminal
disown %1 entfernt den Job aus der Bash-Job-Liste, ohne ihn zu beenden. Damit zählt er nicht mehr zur Session, bekommt beim Logout kein SIGHUP mehr und läuft sauber weiter. disown -h %1 lässt den Job in der Liste, schützt ihn aber trotzdem vor SIGHUP. Vollständige Erklärung im Artikel nohup und disown.
Weiterführende Ressourcen
Externe Quellen
- man bash — Job Control (man7.org) — die offizielle Referenz zu allen Job-Control-Befehlen der Bash
- GNU Bash Manual: Job Control — ausführliche Dokumentation mit allen Job-Specs und Builtins
- Arch Wiki: Bash — Übersicht zur Bash inklusive Job-Control-Sektion
- POSIX: Job Control — Spezifikation, wie Job-Control standardisiert ist
- Greg’s Wiki: BashFAQ Job Control — praktische Antworten auf häufige Fragen
Verwandte Artikel
- nohup und disown — Jobs vom Terminal entkoppeln und gegen SIGHUP schützen
- Signale unter Linux — SIGTSTP, SIGCONT, SIGHUP und ihre Rolle für Job-Control
- kill und Prozesse beenden — Jobs und Process Groups gezielt terminieren
- Prozess-Modell — PID, PGID, Sessions und das Fundament von Job-Control
- Terminal-Multiplexer — tmux und screen für persistente, terminalunabhängige Sessions