Die Bash-Shell unter Linux bietet dir die Möglichkeit, Prozesse im Vorder- und Hintergrund zu steuern. Nutze die Funktionen zur Jobsteuerung und die Signale der Bash, um deine Befehle flexibler auszuführen. Wir zeigen dir, wie es geht.
Grundlagen zu Prozessen
Jedes Mal, wenn du ein Programm unter Linux oder einem unixartigen Betriebssystem startest, wird ein Prozess ins Leben gerufen. Ein „Prozess“ ist die interne Repräsentation des laufenden Programms im Arbeitsspeicher deines Rechners. Für jedes aktive Programm existiert ein Prozess. Eigentlich läuft fast alles, was auf deinem Computer passiert, als Prozess ab. Das beinhaltet deine grafische Desktop-Umgebung (GDE) wie beispielsweise GNOME oder KDE, aber auch System-Dienste (Daemons), die beim Hochfahren des Systems gestartet werden.
Warum läuft fast alles als Prozess? Bestimmte Bash-interne Befehle wie cd, pwd und alias müssen keinen eigenen Prozess starten, um ausgeführt zu werden. Die Bash führt diese Befehle innerhalb ihrer eigenen Instanz im Terminalfenster aus. Diese Befehle sind daher schnell, da kein zusätzlicher Prozess gestartet werden muss. (Du kannst ‚help‘ in dein Terminal eingeben, um eine Liste dieser Bash-internen Befehle zu sehen.)
Prozesse können im Vordergrund laufen und dein Terminal solange blockieren, bis sie beendet sind, oder sie laufen im Hintergrund. Hintergrundprozesse blockieren das Terminalfenster nicht, sodass du weiterarbeiten kannst. Zumindest blockieren sie es nicht, solange sie keine Ausgaben auf dem Bildschirm erzeugen.
Ein anschauliches Beispiel
Wir starten einen einfachen Ping-Befehl, um die Domain etoppc.com anzupingen. Dies wird als Vordergrundprozess ausgeführt.
ping www.wdzwdz.com
Die erwarteten Ergebnisse werden angezeigt und füllen das Terminalfenster nach unten hin aus. Während der Ping-Befehl läuft, kannst du im Terminalfenster nichts anderes tun. Um den Befehl zu beenden, drücke Strg+C.
Ctrl+C
Der Effekt von Strg+C ist im Screenshot hervorgehoben. Ping gibt eine kurze Zusammenfassung und wird dann beendet.
Wiederholen wir den Vorgang. Diesmal drücken wir jedoch Strg+Z anstelle von Strg+C. Der Prozess wird nicht beendet, sondern in den Hintergrund verschoben. Wir erhalten die Kontrolle über das Terminalfenster zurück.
ping www.wdzwdz.com
Ctrl+Z
Der Effekt des Drückens von Strg+Z ist im Screenshot hervorgehoben.
Wir erhalten die Information, dass der Prozess gestoppt wurde. Gestoppt heißt nicht beendet. Es ist wie ein Auto an einem Stoppschild. Wir haben es nicht verschrottet, es steht immer noch bereit und wartet auf den Start. Der Prozess ist jetzt ein Hintergrundjob.
Der Befehl jobs listet die gestarteten Jobs in der aktuellen Terminalsession auf. Und da Jobs (unvermeidlich) Prozesse sind, können wir sie auch mit dem Befehl ps sehen. Verwenden wir beide Befehle und vergleichen ihre Ausgaben. Wir verwenden die Option ‚T‘ (Terminal), um nur Prozesse aufzulisten, die in diesem Terminalfenster ausgeführt werden. Beachte, dass für die Option ‚T‘ kein Bindestrich erforderlich ist.
jobs
ps T
Der Befehl ‚jobs‘ teilt uns Folgendes mit:
[1]: Die Zahl in eckigen Klammern ist die Jobnummer. Diese können wir verwenden, um auf den Job zuzugreifen, wenn wir ihn mit Jobsteuerungsbefehlen kontrollieren müssen.
+: Das Pluszeichen (+) zeigt an, dass dies der Job ist, auf den reagiert wird, wenn wir einen Jobsteuerungsbefehl ohne spezifische Jobnummer verwenden. Dies ist der Standardjob. Der Standardjob ist immer der Job, der zuletzt zur Jobliste hinzugefügt wurde.
Gestoppt: Der Prozess wird nicht ausgeführt.
ping www.wdzwdz.com: Die Befehlszeile, die den Prozess gestartet hat.
Der Befehl ‚ps‘ teilt uns Folgendes mit:
PID: Die Prozess-ID. Jeder Prozess hat eine eindeutige ID.
TTY: Der Pseudoteleprinter (Terminalfenster), von dem der Prozess gestartet wurde.
STAT: Der Status des Prozesses.
TIME: Die vom Prozess verbrauchte CPU-Zeit.
COMMAND: Der Befehl, der den Prozess gestartet hat.
Dies sind die gängigsten Werte für die STAT-Spalte:
D: Ununterbrechbarer Schlaf. Der Prozess befindet sich im Wartezustand, wartet normalerweise auf Eingabe oder Ausgabe und kann nicht unterbrochen werden.
I: Leerlauf.
R: Läuft.
S: Unterbrechbarer Schlaf.
T: Durch ein Jobsteuerungssignal gestoppt.
Z: Ein Zombie-Prozess. Der Prozess wurde beendet, aber nicht vom übergeordneten Prozess „aufgeräumt“.
Der Wert in der STAT-Spalte kann von einem dieser zusätzlichen Indikatoren gefolgt werden:
<: Vordergrund-Prozess mit hoher Priorität.
N: Prozess mit niedriger Priorität.
L: Prozess hat Seiten, die im Speicher gesperrt sind (wird von Echtzeitprozessen verwendet).
S: Session Leader. Ein Session Leader ist der Prozess, der eine Prozessgruppe gestartet hat. Die Shell ist immer ein Session Leader.
l: Multi-Thread-Prozess.
Wir sehen, dass die Bash einen Status von ‚Ss‘ hat. Das große ‚S‘ zeigt an, dass die Bash-Shell sich im unterbrechbaren Schlaf befindet. Sobald wir sie benötigen, wird sie antworten. Das kleine ’s‘ zeigt uns, dass die Shell ein Session Leader ist.
Der Ping-Befehl hat den Status ‚T‘, was bedeutet, dass Ping durch ein Jobsteuerungssignal gestoppt wurde. In diesem Beispiel war das Strg+Z, wodurch wir ihn in den Hintergrund versetzt haben.
Der Befehl ‚ps T‘ selbst hat den Status ‚R‘, was für ‚running‘ steht. Das ‚+‘ zeigt an, dass dieser Prozess ein Mitglied der Vordergrundgruppe ist. Der Befehl ‚ps T‘ läuft also im Vordergrund.
Der ‚bg‘-Befehl
Der Befehl ‚bg‘ wird verwendet, um einen Hintergrundprozess fortzusetzen. Er kann mit oder ohne Jobnummer verwendet werden. Wenn du ihn ohne Jobnummer verwendest, wird der Standardjob in den Vordergrund geholt. Der Prozess läuft dann aber weiterhin im Hintergrund. Du kannst ihm keine Eingaben senden.
Wenn wir den Befehl ‚bg‘ absetzen, setzen wir unseren Ping-Befehl fort:
bg
Der Ping-Befehl läuft weiter, und wir sehen erneut die scrollenden Ausgaben im Terminalfenster. Der Name des neu gestarteten Befehls wird angezeigt. Dies ist im Screenshot hervorgehoben.
Wir haben jedoch ein Problem. Der Job läuft im Hintergrund und akzeptiert keine Eingaben. Wie können wir ihn also stoppen? Strg+C bewirkt nichts. Wir sehen die Eingabe zwar, aber der Hintergrundjob empfängt diese Tastenanschläge nicht und pingt fröhlich weiter.
Wir befinden uns nun in einem seltsamen Mischmodus. Wir können zwar im Terminalfenster etwas eingeben, aber das, was wir eingeben, wird schnell von der scrollenden Ausgabe des Ping-Befehls überschrieben. Alles, was wir eingeben, wirkt sich im Vordergrund aus.
Um unseren Hintergrundjob zu stoppen, müssen wir ihn in den Vordergrund holen und ihn dann stoppen.
Der ‚fg‘-Befehl
Der Befehl ‚fg‘ holt einen Hintergrundjob in den Vordergrund. Wie auch der Befehl ‚bg‘ kann er mit oder ohne Jobnummer verwendet werden. Bei der Verwendung mit einer Jobnummer wird er für einen bestimmten Job ausgeführt. Ohne Jobnummer wird der letzte Befehl verwendet, der in den Hintergrund geschickt wurde.
Wenn wir ‚fg‘ eingeben, wird unser Ping-Befehl in den Vordergrund geholt. Die von uns eingegebenen Zeichen werden mit der Ausgabe des Ping-Befehls vermischt, werden aber von der Shell so verarbeitet, als wären sie in der Befehlszeile eingegeben worden. Und aus Sicht der Bash-Shell ist genau das passiert.
fg
Jetzt, wo der Ping-Befehl wieder im Vordergrund läuft, können wir ihn mit Strg+C beenden.
Ctrl+C
Wir müssen die richtigen Signale senden
Das war nicht gerade elegant. Offensichtlich funktioniert das Ausführen eines Prozesses im Hintergrund am besten, wenn der Prozess keine Ausgaben produziert und keine Eingaben benötigt.
Aber ob elegant oder nicht, unser Beispiel hat folgendes erreicht:
Einen Prozess in den Hintergrund versetzen.
Einen Prozess im Hintergrund in den laufenden Zustand zurückversetzen.
Einen Prozess wieder in den Vordergrund bringen.
Einen Prozess beenden.
Wenn du Strg+C und Strg+Z verwendest, sendest du Signale an den Prozess. Dies sind Kurzformen für die Verwendung des Befehls ‚kill‘. Es gibt 64 verschiedene Signale, die an Prozesse gesendet werden können. Verwende ‚kill -l‘ in der Befehlszeile, um sie aufzulisten. ‚kill‘ ist nicht die einzige Quelle dieser Signale. Einige von ihnen werden automatisch von anderen Prozessen innerhalb des Systems ausgelöst.
Hier sind einige der am häufigsten verwendeten:
SIGHUP: Signal 1. Wird automatisch an einen Prozess gesendet, wenn das Terminal, in dem er läuft, geschlossen wird.
SIGINT: Signal 2. Wird an einen Prozess gesendet, wenn man Strg+C drückt. Der Prozess wird unterbrochen und aufgefordert, sich zu beenden.
SIGQUIT: Signal 3. Wird an einen Prozess gesendet, wenn der Benutzer ein Quit-Signal (Strg+D) sendet.
SIGKILL: Signal 9. Der Prozess wird sofort beendet und versucht nicht, sauber zu schließen. Der Prozess wird ungracefully beendet.
SIGTERM: Signal 15. Dies ist das Standardsignal, das von ‚kill‘ gesendet wird. Es ist das Standard-Beendigungssignal für Programme.
SIGTSTP: Signal 20. Wird an einen Prozess gesendet, wenn man Strg+Z verwendet. Es stoppt den Prozess und versetzt ihn in den Hintergrund.
Wir müssen den Befehl ‚kill‘ verwenden, um Signale zu senden, denen keine Tastenkombinationen zugeordnet sind.
Weitere Jobkontrolle
Ein mit Strg+Z in den Hintergrund verschobener Prozess wird in einen gestoppten Zustand versetzt. Wir müssen den Befehl ‚bg‘ verwenden, um ihn wieder zu starten. Ein Programm als laufenden Hintergrundprozess zu starten ist einfach: Füge ein kaufmännisches Und (&) am Ende der Befehlszeile an.
Obwohl es am besten ist, wenn Hintergrundprozesse nicht in das Terminalfenster schreiben, verwenden wir Beispiele, die dies tun. Wir brauchen etwas in den Screenshots, auf das wir uns beziehen können. Dieser Befehl startet eine Endlosschleife als Hintergrundprozess:
while true; do echo "etoppc.com Loop Process"; sleep 3; done &
Uns werden die Jobnummer und die Prozess-ID des Prozesses mitgeteilt. Unsere Jobnummer ist 1, und die Prozess-ID ist 1979. Wir können diese Identifikatoren verwenden, um den Prozess zu steuern.
Die Ausgabe unserer Endlosschleife beginnt im Terminalfenster zu erscheinen. Wie zuvor können wir die Befehlszeile verwenden, aber alle Befehle, die wir ausgeben, werden mit der Ausgabe des Schleifenprozesses vermischt.
ls
Um unseren Prozess zu stoppen, können wir ‚jobs‘ verwenden, um uns an die Jobnummer zu erinnern, und dann ‚kill‘ verwenden.
‚jobs‘ meldet, dass unser Prozess die Jobnummer 1 hat. Um diese Nummer mit ‚kill‘ zu verwenden, müssen wir ihr ein Prozentzeichen (%) voranstellen.
jobs
kill %1
‚kill‘ sendet das SIGTERM-Signal (Signalnummer 15) an den Prozess, und dieser wird beendet. Beim nächsten Drücken der Eingabetaste wird ein Status des Jobs angezeigt. Er listet den Prozess als „beendet“ auf. Wenn der Prozess nicht auf den ‚kill‘-Befehl reagiert, kannst du ihn ‚aggressiver‘ beenden. Verwende ‚kill‘ mit SIGKILL (Signalnummer 9). Setze die Nummer 9 einfach zwischen den Befehl ‚kill‘ und die Jobnummer.
kill 9 %1
Zusammenfassung der besprochenen Punkte
Strg+C: Sendet SIGINT (Signal 2) an den Prozess – falls dieser Eingaben akzeptiert – und weist ihn an, sich zu beenden.
Strg+D: Sendet SIGQUIT (Signal 3) an den Prozess – falls dieser Eingaben akzeptiert – und weist ihn an, sich zu beenden.
Strg+Z: Sendet SIGSTP (Signal 20) an den Prozess und weist ihn an, anzuhalten (suspendieren) und ein Hintergrundprozess zu werden.
jobs: Listet die Hintergrundjobs auf und zeigt ihre Jobnummern an.
bg job_number: Startet einen Hintergrundprozess wieder. Wenn keine Jobnummer angegeben wird, wird der letzte Prozess verwendet, der in einen Hintergrundjob umgewandelt wurde.
fg job_number: Holt einen Hintergrundprozess in den Vordergrund und startet ihn wieder. Wenn keine Jobnummer angegeben wird, wird der letzte Prozess verwendet, der in einen Hintergrundjob umgewandelt wurde.
Befehlszeile &: Das Hinzufügen eines kaufmännischen Und-Zeichens (&) am Ende einer Befehlszeile führt diesen Befehl als Hintergrundjob aus.
kill %job_number: Sendet SIGTERM (Signal 15) an den Prozess, um ihn zu beenden.
kill 9 %job_number: Sendet SIGKILL (Signal 9) an den Prozess und beendet ihn abrupt.