6121 Stimmen

Wie kann ich ein Programm ausführen oder einen Systembefehl aufrufen?

Wie rufe ich einen externen Befehl in Python auf, als hätte ich ihn in einer Shell oder Eingabeaufforderung eingegeben?

0 Stimmen

Ich verstehe das nicht, was ist falsch an import os; os.system('pip list | grep anatome') ? Zumindest kann man damit Piping machen, wie mein Beispiel zeigt. Es ist nicht klar, wie man das mit import subprocess; subprocess.run(["ls", "-l"]) .

5812voto

David Cournapeau Punkte 74679

Verwenden Sie die subprocess Modul in der Standardbibliothek:

import subprocess
subprocess.run(["ls", "-l"])

Der Vorteil von subprocess.run über os.system ist, dass sie flexibler ist (Sie können die stdout , stderr le "real"-Statuscode , besser Fehlerbehandlung usw...).

Sogar die Dokumentation für os.system empfiehlt die Verwendung von subprocess stattdessen:

Die subprocess Modul bietet leistungsfähigere Möglichkeiten zum Starten neuer Prozesse und zum Abrufen ihrer Ergebnisse; die Verwendung dieses Moduls ist der Verwendung dieser Funktion vorzuziehen. Siehe die Ersetzen älterer Funktionen durch das subprocess-Modul Abschnitt in der subprocess Dokumentation für einige hilfreiche Rezepte.

Unter Python 3.4 und früher, verwenden Sie subprocess.call anstelle von .run :

subprocess.call(["ls", "-l"])

9 Stimmen

Gibt es eine Möglichkeit, die Variablenersetzung zu nutzen? IE Ich habe versucht, Folgendes zu tun echo $PATH durch die Verwendung von call(["echo", "$PATH"]) aber es wurde nur die wörtliche Zeichenkette wiedergegeben $PATH anstatt eine Ersetzung vorzunehmen. Ich weiß, dass ich die PATH-Umgebungsvariable erhalten könnte, aber ich frage mich, ob es eine einfache Möglichkeit gibt, den Befehl genau so zu verhalten, als ob ich ihn in Bash ausgeführt hätte.

0 Stimmen

@KevinWheeler Sie müssen die shell=True damit das funktioniert.

75 Stimmen

@KevinWheeler Sie sollten NICHT shell=True Zu diesem Zweck verfügt Python über os.path.expandvars . In Ihrem Fall können Sie schreiben: os.path.expandvars("$PATH") . @SethMMorton bitte überdenken Sie Ihren Kommentar -> Warum man nicht shell=True verwenden sollte

3571voto

Eli Courtwright Punkte 174547

Zusammenfassung der Möglichkeiten zum Aufruf externer Programme, einschließlich ihrer Vor- und Nachteile:

  1. os.system übergibt den Befehl und die Argumente an die Shell Ihres Systems. Das ist praktisch, weil Sie auf diese Weise mehrere Befehle gleichzeitig ausführen und Pipes sowie eine Umleitung von Ein- und Ausgaben einrichten können. Zum Beispiel:

    os.system("some_command < input_file | another_command > output_file")  

    Dies ist zwar praktisch, aber Sie müssen die Escape-Funktion für Shell-Zeichen wie Leerzeichen usw. manuell anwenden. Andererseits können Sie auf diese Weise auch Befehle ausführen, bei denen es sich lediglich um Shell-Befehle und nicht um externe Programme handelt.

  2. os.popen bewirkt dasselbe wie os.system mit dem Unterschied, dass Sie damit ein dateiähnliches Objekt erhalten, mit dem Sie auf die Standardeingabe/-ausgabe des Prozesses zugreifen können. Es gibt 3 weitere Varianten von popen, die alle etwas anders mit der E/A umgehen. Wenn Sie alles als Zeichenkette übergeben, wird Ihr Befehl an die Shell weitergeleitet; wenn Sie sie als Liste übergeben, müssen Sie sich nicht um die Escape-Funktion kümmern. Beispiel:

    print(os.popen("ls -l").read())
  3. subprocess.Popen . Dies ist als Ersatz gedacht für os.popen Sie hat aber den Nachteil, dass sie etwas komplizierter ist, weil sie so umfassend ist. Man würde zum Beispiel sagen:

    print subprocess.Popen("echo Hello World", shell=True, stdout=subprocess.PIPE).stdout.read()

    anstelle von

    print os.popen("echo Hello World").read()

    aber es ist schön, alle Optionen in einer einheitlichen Klasse zu haben, anstatt 4 verschiedene Popenfunktionen. Siehe die Dokumentation .

  4. subprocess.call . Dies ist im Grunde genau wie die Popen Klasse und nimmt alle dieselben Argumente an, wartet aber einfach, bis der Befehl abgeschlossen ist, und gibt den Rückgabewert an. Zum Beispiel:

    return_code = subprocess.call("echo Hello World", shell=True)
  5. subprocess.run . Nur Python 3.5+. Ähnlich wie oben, aber noch flexibler und gibt ein CompletedProcess Objekt, wenn die Ausführung des Befehls beendet ist.

  6. os.fork , os.exec , os.spawn sind ihren Gegenstücken in der Sprache C ähnlich, aber ich empfehle nicht, sie direkt zu verwenden.

Die subprocess Modul sollten Sie wahrscheinlich verwenden.

Beachten Sie bitte, dass Sie bei allen Methoden, bei denen Sie den endgültigen Befehl, der von der Shell ausgeführt werden soll, als Zeichenkette übergeben, für das Escaping verantwortlich sind. Es gibt ernsthafte Auswirkungen auf die Sicherheit wenn ein Teil der übergebenen Zeichenkette nicht vollständig vertrauenswürdig ist. Zum Beispiel, wenn ein Benutzer einen beliebigen Teil der Zeichenkette eingibt. Wenn Sie unsicher sind, verwenden Sie diese Methoden nur mit Konstanten. Um Ihnen einen Hinweis auf die Auswirkungen zu geben, betrachten Sie diesen Code:

print subprocess.Popen("echo %s " % user_input, stdout=PIPE).stdout.read()

und stellen Sie sich vor, dass der Benutzer etwas eingibt " my mama didnt love me && rm -rf / ", was das gesamte Dateisystem löschen könnte.

57 Stimmen

Gute Antwort/Erläuterung. Wie rechtfertigt diese Antwort das Motto von Python, wie es in diesem Artikel beschrieben wird? fastcompany.com/3026446/ "Stilistisch haben Perl und Python unterschiedliche Philosophien. Das bekannteste Motto von Perl ist "Es gibt mehr als einen Weg, es zu tun". Python ist so konzipiert, dass es nur einen offensichtlichen Weg gibt." Es sollte eigentlich umgekehrt sein! In Perl kenne ich nur zwei Möglichkeiten, einen Befehl auszuführen - mit back-tick oder open .

29 Stimmen

Wenn Sie Python 3.5+ verwenden, benutzen Sie subprocess.run() . docs.python.org/3.5/library/subprocess.html#subprocess.run

11 Stimmen

Normalerweise muss man wissen, was mit STDOUT und STDERR des Kindprozesses geschieht, denn wenn sie ignoriert werden, wird der Kindprozess unter bestimmten (recht häufigen) Bedingungen irgendwann einen Systemaufruf zum Schreiben in STDOUT (auch STDERR?) absetzen, der den vom Betriebssystem für den Prozess bereitgestellten Ausgabepuffer überschreiten würde, und das Betriebssystem wird ihn blockieren, bis ein anderer Prozess aus diesem Puffer liest. Mit den derzeit empfohlenen Methoden, subprocess.run(..) was genau bedeutet "Dies erfasst standardmäßig weder stdout noch stderr." andeuten? Was ist mit subprocess.check_output(..) und STDERR?

440voto

EmmEff Punkte 7393

Typische Umsetzung:

import subprocess

p = subprocess.Popen('ls', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line in p.stdout.readlines():
    print line,
retval = p.wait()

Es steht Ihnen frei, mit den Daten zu tun, was Sie wollen. stdout Daten in der Leitung. In der Tat können Sie diese Parameter einfach weglassen ( stdout= y stderr= ) und es wird sich verhalten wie os.system() .

60 Stimmen

.readlines() liest tous Zeilen auf einmal, d.h. er blockiert, bis der Unterprozess sich beendet (sein Ende der Pipe schließt). Um in Echtzeit zu lesen (wenn es keine Pufferungsprobleme gibt), könnten Sie: for line in iter(p.stdout.readline, ''): print line,

4 Stimmen

Könnten Sie näher erläutern, was Sie mit "wenn es keine Pufferungsprobleme gibt" meinen? Wenn der Prozess definitiv blockiert, blockiert auch der Aufruf des Unterprozesses. Das Gleiche könnte auch bei meinem ursprünglichen Beispiel passieren. Was könnte sonst noch in Bezug auf die Pufferung passieren?

20 Stimmen

Der Kindprozess kann im nicht-interaktiven Modus die Blockpufferung anstelle der Zeilenpufferung verwenden, so dass p.stdout.readline() (Anmerkung: keine s am Ende) sieht keine Daten, bis das Kind seinen Puffer füllt. Wenn das Kind nicht viele Daten produziert, wird die Ausgabe nicht in Echtzeit erfolgen. Siehe den zweiten Grund in F: Warum nicht einfach eine Pipe (popen()) verwenden? . Es werden einige Umgehungsmöglichkeiten angeboten in dieser Antwort (pexpect, pty, stdbuf)

278voto

newtover Punkte 29616

Einige Hinweise zum Trennen des Kindprozesses vom aufrufenden Prozess (Starten des Kindprozesses im Hintergrund).

Angenommen, Sie wollen eine lange Aufgabe von einem CGI-Skript aus starten. Das heißt, der untergeordnete Prozess sollte länger laufen als der CGI-Skript-Ausführungsprozess.

Das klassische Beispiel aus der Dokumentation des Subprozessmoduls lautet:

import subprocess
import sys

# Some code here

pid = subprocess.Popen([sys.executable, "longtask.py"]) # Call subprocess

# Some more code here

Die Idee dahinter ist, dass man in der Zeile "call subprocess" nicht warten will, bis longtask.py fertig ist. Aber es ist nicht klar, was nach der Zeile "some more code here" aus dem Beispiel passiert.

Meine Zielplattform war FreeBSD, aber die Entwicklung fand unter Windows statt, also habe ich das Problem zuerst unter Windows gelöst.

Unter Windows (Windows XP) wird der übergeordnete Prozess nicht beendet, bevor longtask.py seine Arbeit beendet hat. Das ist nicht das, was Sie in einem CGI-Skript wollen. Das Problem ist nicht spezifisch für Python; in der PHP-Gemeinschaft sind die Probleme die gleichen.

Die Lösung ist die Übergabe von DETACHED_PROCESS Flagge für Prozesserstellung auf die zugrunde liegende CreateProcess-Funktion in der Windows-API. Wenn Sie pywin32 installiert haben, können Sie das Flag aus dem win32process-Modul importieren, ansonsten sollten Sie es selbst definieren:

DETACHED_PROCESS = 0x00000008

pid = subprocess.Popen([sys.executable, "longtask.py"],
                       creationflags=DETACHED_PROCESS).pid

/* UPD 2015.10.27 @eryksun merkt in einem Kommentar unten an, dass das semantisch korrekte Flag CREATE_NEW_CONSOLE (0x00000010) ist */

Unter FreeBSD gibt es ein weiteres Problem: Wenn der Elternprozess beendet ist, beendet er auch die Kindprozesse. Und das ist auch nicht das, was man in einem CGI-Skript will. Einige Experimente zeigten, dass das Problem in der gemeinsamen Nutzung von sys.stdout zu liegen schien. Und die funktionierende Lösung war die folgende:

pid = subprocess.Popen([sys.executable, "longtask.py"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)

Ich habe den Code nicht auf anderen Plattformen überprüft und kenne die Gründe für das Verhalten unter FreeBSD nicht. Wenn jemand etwas weiß, bitte ich um einen Hinweis. Googeln über das Starten von Hintergrundprozessen in Python hat bisher nichts ergeben.

0 Stimmen

Ich habe eine mögliche "Macke" bei der Entwicklung von py2exe-Anwendungen in pydev+eclipse bemerkt. ich konnte feststellen, dass das Hauptskript nicht losgelöst wurde, weil das Ausgabefenster von eclipse nicht beendet wurde; selbst wenn das Skript bis zum Ende ausgeführt wird, wartet es noch auf Rückgaben. aber als ich versucht habe, in eine ausführbare py2exe-Datei zu kompilieren, tritt das erwartete Verhalten auf (die Prozesse werden als losgelöst ausgeführt und dann beendet). ich bin mir nicht sicher, aber der Name der ausführbaren Datei ist nicht mehr in der Prozessliste. dies funktioniert bei allen Ansätzen (os.system("start *"), os.spawnl mit os.P_DETACH, subprocs, usw.)

0 Stimmen

Windows-Problem: obwohl ich einen Prozess mit DETACHED_PROCESS gestartet habe, wurden beim Beenden meines Python-Daemons alle von ihm geöffneten Ports nicht freigegeben, bis alle gestarteten Prozesse beendet waren. WScript.Shell hat alle meine Probleme gelöst. Beispiel hier: pastebin.com/xGmuvwSx

3 Stimmen

Benötigen Sie möglicherweise auch das Kennzeichen CREATE_NEW_PROCESS_GROUP. Siehe Popen wartet auf untergeordneten Prozess, auch wenn der unmittelbare untergeordnete Prozess beendet ist

230voto

nimish Punkte 4440
import os
os.system("your command")

Beachten Sie, dass dies gefährlich ist, da der Befehl nicht bereinigt wird. Ich überlasse es Ihnen, nach der entsprechenden Dokumentation zu den Modulen "os" und "sys" zu googeln. Es gibt eine Reihe von Funktionen (exec* und spawn*), die ähnliche Dinge bewirken.

20 Stimmen

Keine Ahnung, was ich vor fast zehn Jahren gemeint habe (achten Sie auf das Datum!), aber wenn ich raten müsste, würde ich sagen, dass keine Validierung erfolgt.

4 Stimmen

Diese sollte nun auf subprocess als eine etwas vielseitigere und tragbare Lösung. Die Ausführung externer Befehle ist natürlich von Natur aus nicht portabel (Sie müssen sicherstellen, dass der Befehl auf jeder Architektur, die Sie unterstützen müssen, verfügbar ist) und die Übergabe von Benutzereingaben als externer Befehl ist von Natur aus unsicher.

3 Stimmen

Beachten Sie den Zeitstempel: Die "richtige" Antwort hat 40 Mal mehr Stimmen und ist Antwort Nr. 1.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X