So starten Sie externe Prozesse mit Python und dem Subprozessmodul

So starten Sie externe Prozesse mit Python und dem Subprozessmodul

In unseren Automatisierungsskripten müssen wir häufig externe Programme starten und überwachen, um unsere gewünschten Aufgaben zu erledigen. Bei der Arbeit mit Python können wir das Subprozessmodul verwenden, um diese Operationen auszuführen. Dieses Modul ist Teil der Standardbibliothek der Programmiersprache. In diesem Tutorial werden wir es uns kurz ansehen und die Grundlagen seiner Nutzung lernen.

In diesem Tutorial lernen Sie:

  • So verwenden Sie die Funktion „Run“, um einen externen Prozess zu erzeugen
  • So erfassen Sie einen Prozessstandardausgang und Standardfehler
  • So überprüfen Sie den existierenden Status eines Prozesses und steigern eine Ausnahme, wenn er fehlschlägt
  • Wie man einen Prozess in eine Zwischenschale ausführt
  • So setzen Sie eine Auszeit für einen Prozess
  • So verwenden Sie die Popen -Klasse direkt, um zwei Prozesse zu leiten
So starten Sie externe Prozesse mit Python und dem Subprozessmodul

Softwareanforderungen und Konventionen verwendet

Softwareanforderungen und Linux -Befehlszeilenkonventionen
Kategorie Anforderungen, Konventionen oder Softwareversion verwendet
System Verteilung unabhängig
Software Python3
Andere Kenntnis von Python und objektorientiertem Programmieren
Konventionen # - Erfordert, dass gegebene Linux -Commands mit Root -Berechtigungen entweder direkt als Stammbenutzer oder mithilfe von verwendet werden können sudo Befehl
US

Die Funktion „Run“

Der laufen Funktion wurde zu dem hinzugefügt Subprozess Modul nur in relativ neueren Versionen von Python (3.5). Die Verwendung ist nun die empfohlene Möglichkeit, Prozesse zu laken und die häufigsten Anwendungsfälle abzudecken. Lassen Sie uns vor allem anderen die einfachste Verwendung sehen. Angenommen, wir wollen die laufen lassen ls -al Befehl; In einer Python -Hülle würden wir rennen:

>>> Subprozess importieren >>> process = subprocess.run (['ls', '-l', '-a']) 

Die Ausgabe des externen Befehls wird auf dem Bildschirm angezeigt:

Gesamt 132 DRWX------. 22 EGDOC EGDOC 4096 30. November 12:18 . DRWXR-XR-X. 4 Wurzelwurzel 4096 22. November 13: 11… -RW-------. 1 EGDOC EGDOC 10438 1 12:54 Uhr .BASH_HISTORY -RW-R-R--. 1 EGDOC EGDOC 18. Juli 27 15:10 .Bash_logout […] 

Hier haben wir gerade das erste, obligatorische Argument verwendet, das von der Funktion akzeptiert wird, die eine Sequenz sein kann, die einen Befehl und seine Argumente (wie im Beispiel) oder eine Zeichenfolge „beschreibt“, die beim Ausführen mit dem verwendet werden sollte Shell = wahr Argument (wir werden es später sehen).

Erfassen des Befehls stdout und stderr

Was ist, wenn wir nicht möchten, dass die Ausgabe des Vorgangs auf dem Bildschirm angezeigt wird, sondern stattdessen erfasst werden kann, damit er nach dem Ablauf des Prozesses verwiesen werden kann? In diesem Fall können wir die festlegen capture_output Argument der Funktion zu WAHR:

>>> process = subprocess.run (['ls', '-l', '-a'], capture_output = true) 

Wie können wir den Ausgang (STDOut und Stderr) des Prozesses danach abrufen?? Wenn Sie die obigen Beispiele beobachten, können Sie sehen, dass wir die verwendet haben Verfahren Variable auf Referenz, was von der zurückgegeben wird laufen Funktion: a Fertigerprozess Objekt. Dieses Objekt repräsentiert den Prozess, der von der Funktion gestartet wurde und viele nützliche Eigenschaften aufweist. Unter den anderen, Stdout Und Stderr werden verwendet, um die entsprechenden Deskriptoren des Befehls zu „speichern“, wenn, wie wir sagten, die capture_output Argument ist auf WAHR. In diesem Fall, um das zu bekommen Stdout des Prozesses würden wir ausführen:

>>> Prozess.Stdout 

Stdout und Stderr werden als gespeichert als Bytessequenzen standardmäßig. Wenn wir wollen, dass sie als Saiten gespeichert werden, müssen wir die festlegen Text Argument der laufen Funktion zu WAHR.



Verwalten Sie einen Prozessfehler

Der Befehl, den wir in den vorherigen Beispielen ausgeführt haben, wurde ohne Fehler ausgeführt. Beim Schreiben eines Programms sollten jedoch alle Fälle berücksichtigt werden. Was ist also, wenn ein hervorgerufener Prozess fehlschlägt? Standardmäßig würde nichts „Besonderes“ passieren. Lassen Sie uns ein Beispiel sehen; Wir laufen die ls Befehl erneut und versuchen Sie, den Inhalt der aufzulisten /Wurzel Verzeichnis, das normalerweise unter Linux von normalen Benutzern nicht lesbar ist:

>>> process = subprocess.run (['ls', '-l', '-a', '/root']) 

Eine Sache, die wir tun können, um zu überprüfen, ob ein gestarteter Prozess fehlgeschlagen ist, ist die Überprüfung des existierenden Status, der in der gespeichert ist Rückgabe Code Eigentum des Fertigerprozess Objekt:

>>> Prozess.Returncode 2 

Sehen? In diesem Fall die Rückgabe Code War 2, bestätigte, dass der Prozess auf ein Berechtigungsproblem stieß und nicht erfolgreich abgeschlossen wurde. Wir könnten die Ausgabe eines Prozesses auf diese Weise testen, oder eleganter konnten wir machen, damit eine Ausnahme erhöht wird, wenn ein Fehler auftritt. Geben Sie die überprüfen Argument der laufen Funktion: Wenn es auf eingestellt ist WAHR und ein hervorgebrachter Prozess scheitert, die PROCESSERROR genannt Ausnahme wird erhöht:

>>> process = subprocess.run (['ls', '-l', '-a', '/root'], check = true) ls: Verzeichnis kann nicht öffnen '/root': Erlaubnis verweigert TraceBack (letztes Anruf in letzter Zeit): Datei "" "" , Zeile 1, in der Datei "/usr/lib64/python3.9/Subprozess.Py ", Zeile 524, in Run Raise Calling Processirror (Retcode, Prozess.Args, Subprozess.CallingProceserror: Befehl '[' ls ',' -l ',' -a ','/root ']' zurückgegeben. 

Handhabung Ausnahmen In Python ist es ziemlich einfach. Um einen Prozessfehler zu verwalten, können wir so etwas schreiben wie:

>>> Versuchen Sie:… process = subprocess.run (['ls', '-l', '-a', '/root'], check = true)… außer Subprozess.CallingProceserror als E:… # Nur ein Beispiel, etwas Nützliches, um den Fehler zu verwalten, sollte durchgeführt werden!… Print (f "e.cmd fehlgeschlagen!") ... ls: Verzeichnis kann nicht öffnen '/root': Erlaubnis verweigert ['ls', '-l', '-a', '/root'] fehlgeschlagen! >>> 

Der PROCESSERROR genannt Die Ausnahme, wie wir sagten 0 Status. Das Objekt hat Eigenschaften wie Rückgabe Code, CMD, Stdout, Stderr; Was sie darstellen, ist ziemlich offensichtlich. Im obigen Beispiel zum Beispiel haben wir einfach die verwendet CMD Eigenschaft, um die Sequenz zu melden, die verwendet wurde, um den Befehl und seine Argumente in der von uns geschriebenen Nachricht zu beschreiben, als die Ausnahme eintrat.

Führen Sie einen Prozess in einer Shell aus

Die Prozesse mit dem gestartet laufen Funktion werden „direkt“ ausgeführt. Dies bedeutet, dass keine Shell verwendet wird, um sie zu starten: Daher stehen für den Prozess keine Umgebungsvariablen zur Verfügung, und es werden keine Shell -Erweiterungen durchgeführt. Sehen wir uns ein Beispiel an, das die Verwendung des $ Home Variable:

>>> process = subprocess.run (['ls', '-al', '$ home']) ls: Kann nicht zugreifen '$ home': Keine solche Datei oder Verzeichnis 

Wie Sie das sehen können $ Home Variable wurde nicht erweitert. Auf diese Weise wird empfohlen, Prozesse auszuführen, um potenzielle Sicherheitsrisiken zu vermeiden. In bestimmten Fällen müssen wir jedoch eine Shell als Zwischenprozess aufrufen Hülse Parameter der laufen Funktion zu WAHR. In solchen Fällen ist es vorzuziehen, den zu ausgeführten Befehl und seine Argumente als a anzugeben Saite:

>>> process = subprocess.run ('ls -al $ home', Shell = true) Gesamt 136 DRWX------. 23 EGDOC EGDOC 4096 Dez 3 09:35 . DRWXR-XR-X. 4 Wurzelwurzel 4096 22. November 13: 11… -RW-------. 1 EGDOC EGDOC 11885 Dez 3 09:35 .BASH_HISTORY -RW-R-R--. 1 EGDOC EGDOC 18. Juli 27 15:10 .Bash_logout […] 

Alle in der Benutzerumgebung vorhandenen Variablen können verwendet werden, um eine Shell als Zwischenprozess aufzurufen: Obwohl dies nützlich aussehen kann, kann dies eine Quelle von Problemen sein, insbesondere bei potenziell gefährlichen Eingaben, was zu Problemen führen kann, was dazu führen kann Muschelinjektionen. Ausführen eines Vorgangs mit Shell = wahr ist daher entmutigt und sollte nur in sicheren Fällen verwendet werden.



Angabe einer Zeitüberschreitung für einen Prozess

Wir wollen normalerweise nicht, dass sich Fehlverfahren für immer auf unserem System laufen, sobald sie gestartet werden. Wenn wir das verwenden Auszeit Parameter der laufen Funktion können wir eine Zeitspanne in Sekunden angeben, die der Prozess abgeschlossen werden sollte, um abzuschließen. Wenn es in dieser Zeit nicht abgeschlossen ist, wird der Prozess mit a getötet Sigkill Signal, was, wie wir wissen, nicht von einem Prozess gefangen werden kann. Lassen Sie uns dies demonstrieren, indem wir einen langjährigen Prozess hervorbringen und in Sekunden einen Zeitüberschreitungen anbieten:

>>> process = subprocess.rennen (['Ping', 'Google.com '], timeout = 5) ping google.com (216.58.206.46) 56 (84) Datenbytes von Daten. 64 Bytes von Mil07S07-in-F14.1e100.Netz (216.58.206.46): ICMP_SEQ = 1 TTL = 113 Zeit = 29.3 ms 64 Bytes von LHR35S10-in-F14.1e100.Netz (216.58.206.46): ICMP_SEQ = 2 TTL = 113 Zeit = 28.3 ms 64 Bytes von LHR35S10-in-F14.1e100.Netz (216.58.206.46): ICMP_SEQ = 3 TTL = 113 Zeit = 28.5 ms 64 Bytes von LHR35S10-in-F14.1e100.Netz (216.58.206.46): ICMP_SEQ = 4 TTL = 113 Zeit = 28.5 ms 64 Bytes von LHR35S10-in-F14.1e100.Netz (216.58.206.46): ICMP_SEQ = 5 TTL = 113 Zeit = 28.1 MS TraceBack (letzte Anruf Letzte): Datei "", Zeile 1, in der Datei "/usr/lib64/python3.9/Subprozess.Py ", Zeile 503, in Run stdout, stderr = prozess.Kommunikation (Eingabe, Timeout = Timeout) Datei "/usr/lib64/python3.9/Subprozess.Py ", Zeile 1130, in kommunizierter Stdout, stderr = self._communicate (Eingabe, Endzeit, Zeitüberschreitungsdatei "/usr/lib64/python3.9/Subprozess.Py ", Zeile 2003, in _ -communicate self.Warten Sie (Timeout = Selbst._remaining_time (endzeit)) Datei "/usr/lib64/python3.9/Subprozess.Py ", Zeile 1185, kehren Sie selbst zurück._wait (timeout = timeout) Datei "/usr/lib64/python3.9/Subprozess.Py ", Zeile 1907, in _wait erhöhen.Args, Zeitüberschreitungen) Subprozess.Timeoutexpirepired: Befehl '[' Ping ',' Google.com ']' zeitlich nach 4.999826977029443 Sekunden 

Im obigen Beispiel haben wir die gestartet Klingeln Befehl ohne Angabe einer festen Menge von Echoanfrage Pakete, daher könnte es möglicherweise für immer laufen. Wir haben auch eine Zeitüberschreitung von angegeben 5 Sekunden über die Auszeit Parameter. Wie wir das Programm zunächst beobachten können, aber das, aber das Zeitüberschreitung Die Ausnahme wurde erhöht, als die angegebene Menge von Sekunden erreicht wurde und der Prozess getötet wurde.

Die Funktionen für Anrufe, check_output und check_call

Wie wir bereits sagte, die laufen Funktion ist die empfohlene Möglichkeit, einen externen Prozess auszuführen und sollte die meisten Fälle abdecken. Bevor es in Python 3 vorgestellt wurde.5, die drei Haupt -API -Funktionen auf hoher Ebene, die zum Starten eines Prozesses verwendet wurden Forderung, check_output Und check_call; Lassen Sie uns sie kurz sehen.

Zunächst die Forderung Funktion: Es wird verwendet, um den von der beschriebenen Befehl auszuführen Args Parameter; Es wartet, bis der Befehl abgeschlossen ist, und gibt seine zurück Rückgabe Code. Es entspricht ungefähr der Grundverwendung des laufen Funktion.

Der check_call Funktionsverhalten ist praktisch das gleiche wie das der laufen Funktion, wenn die überprüfen Parameter wird auf eingestellt WAHR: Es führt den angegebenen Befehl aus und wartet darauf, dass er abgeschlossen ist. Wenn sein Status nicht ist 0, A PROCESSERROR genannt Ausnahme wird erhöht.

Endlich, das check_output Funktion: Es funktioniert ähnlich wie check_call, Aber kehrt zurück Die Programmausgabe: Es wird nicht angezeigt, wenn die Funktion ausgeführt wird.

Mit der Popen -Klasse auf einer niedrigeren Ebene arbeiten

Bisher haben wir insbesondere die API -Funktionen auf hohen Ebenen im Subprozessmodul untersucht laufen. All diese Funktionen interagieren unter der Motorhaube mit dem Popen Klasse. Aus diesem Grund müssen wir in den meisten Fällen nicht direkt damit arbeiten. Wenn jedoch mehr Flexibilität erforderlich ist, erstellen Sie Popen Objekte werden direkt notwendig.



Nehmen wir zum Beispiel an, wir möchten zwei Prozesse anschließen und das Verhalten einer Schale „Rohr“ neu erstellen. Wie wir wissen, wenn wir zwei Befehle in der Hülle putzen, ist die Standardausgabe des einen auf der linken Seite des Rohrs (|) wird als Standardeingabe des rechts davon verwendet (überprüfen Sie diesen Artikel über Shell -Umleitung, wenn Sie mehr über das Thema erfahren möchten). Im folgenden Beispiel werden die beiden Befehle in einer Variablen gespeichert:

$ output = "$ (dmesg | grep sda)" 

Um dieses Verhalten mit dem Subprozessmodul zu emulieren, ohne das festlegen zu müssen Hülse Parameter zu WAHR Wie wir zuvor gesehen haben, müssen wir die verwenden Popen Klasse direkt:

dmesg = subprozess.Popen (['dmesg'], stdout = subprozess.Pfeife) Grep = Subprozess.Popen (['Grep', 'SDA'], stdin = dmesg.stdout) dmesg.Stdout.close () output = grep.comunicate () [0] 

Um das obige Beispiel zu verstehen, müssen wir uns daran erinnern, dass ein Prozess mit der Verwendung des Popen Die Klasse blockiert direkt die Ausführung des Skripts nicht, da es jetzt gewartet wird.

Das erste, was wir im Code -Snippet oben gemacht haben, war, das zu erstellen Popen Objekt, das die darstellt dmesg Verfahren. Wir setzen die Stdout dieses Prozesses zu Subprozess.ROHR: Dieser Wert zeigt an, dass ein Rohr zum angegebenen Strom geöffnet werden sollte.

Wir haben eine andere Instanz der erstellt Popen Klasse für die Grep Verfahren. Im Popen Konstruktor haben wir den Befehl und seine Argumente natürlich angegeben, aber hier ist der wichtige Teil, wir setzen die Standardausgabe der dmesg Prozess, der als Standardeingabe verwendet werden soll (stdin = dmesg.Stdout), also um die Hülle nachzubilden
Rohrverhalten.

Nach dem Erstellen der Popen Objekt für die Grep Befehl, wir haben das geschlossen Stdout Strom der dmesg Prozess verwenden die schließen() Methode: Dies ist, wie in der Dokumentation angegeben, erforderlich, damit der erste Prozess ein Sigpipe -Signal empfängt. Versuchen wir zu erklären, warum. Wenn zwei Prozesse mit einem Rohr verbunden sind, erhält der letztere einen vor dem One links (DMESG) vor dem One links (DMESG), wenn derjenige rechts von der Rohr (Grep in unserem Beispiel) verlässt Sigpipe
Signal (gebrochenes Rohr) und standardmäßig endet sich selbst.

Bei der Replikation des Verhaltens einer Pfeife zwischen zwei Befehlen in Python gibt es jedoch ein Problem: die Stdout des ersten Prozesses wird sowohl im übergeordneten Skript als auch in der Standardeingabe des anderen Prozesses geöffnet. Auf diese Weise, auch wenn die Grep Der Prozess endet, die Pipe bleibt im Anruferprozess (unser Skript) weiterhin geöffnet, daher wird der erste Vorgang niemals die empfangen Sigpipe Signal. Deshalb müssen wir das schließen Stdout Stream des ersten Prozesses in unserem
Hauptskript nach dem Start des zweiten.

Das Letzte, was wir getan haben, war, das anzurufen kommunizieren() Methode auf der Grep Objekt. Diese Methode kann verwendet werden, um die Eingabe optional an einen Prozess zu übergeben. Es wartet, bis der Prozess beendet wird und gibt ein Tupel zurück, bei dem das erste Mitglied der Prozess ist Stdout (auf die auf die verwiesen wird Ausgang Variable) und die zweite der Prozess Stderr.

Schlussfolgerungen

In diesem Tutorial sahen wir die empfohlene Art, externe Prozesse mit Python zu erzeugen Subprozess Modul und die laufen Funktion. Die Verwendung dieser Funktion sollte für die meisten Fälle ausreichen. Wenn jedoch ein höheres Maß an Flexibilität erforderlich ist, muss man die verwenden Popen Klasse direkt. Wie immer empfehlen wir, uns das anzusehen
Unterprozessdokumentation für einen vollständigen Überblick über die Unterschrift der Funktionen und Klassen in der in verfügbaren Klassen in
das Modul.

Verwandte Linux -Tutorials:

  • Eine Einführung in Linux -Automatisierung, Tools und Techniken
  • Mastering -Bash -Skriptschleifen beherrschen
  • Dinge zu installieren auf Ubuntu 20.04
  • Verschachtelte Schleifen in Bash -Skripten
  • So verwenden Sie den Befehl TCPDump unter Linux
  • Mint 20: Besser als Ubuntu und Microsoft Windows?
  • Umgang mit Benutzereingaben in Bash -Skripten
  • GDB -Debugging -Tutorial für Anfänger
  • Dinge zu tun nach der Installation Ubuntu 20.04 fokale Fossa Linux
  • So überwachen Sie die Netzwerkaktivität auf einem Linux -System