Aufrufen eines externen Befehls aus Python


Antworten:


4695

Schauen Sie sich das Unterprozessmodul in der Standardbibliothek an:

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

Der Vorteil subprocessgegenüber systemist , dass es flexibler ist (Sie das bekommen kann stdout, stderrdie „echten“ Statuscode, eine bessere Fehlerbehandlung, etc ...).

In der offiziellen Dokumentation wird das subprocessModul gegenüber der Alternative empfohlen os.system():

Das subprocessModul bietet leistungsfähigere Funktionen zum Laichen neuer Prozesse und zum Abrufen ihrer Ergebnisse. Die Verwendung dieses Moduls ist der Verwendung dieser Funktion vorzuziehen [ os.system()].

Der Abschnitt Ersetzen älterer Funktionen durch das Unterprozessmodul in der subprocessDokumentation enthält möglicherweise einige hilfreiche Rezepte.

Verwenden Sie für Versionen von Python vor 3.5 call:

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

Gibt es eine Möglichkeit, die Variablensubstitution zu verwenden? IE habe ich versucht, echo $PATHindem ich verwendet habe call(["echo", "$PATH"]), aber es hat nur die Literalzeichenfolge wiedergegeben, $PATHanstatt eine Ersetzung vorzunehmen. Ich weiß, dass ich die Umgebungsvariable PATH erhalten könnte, aber ich frage mich, ob es eine einfache Möglichkeit gibt, den Befehl genau so zu verhalten, als hätte ich ihn in bash ausgeführt.
Kevin Wheeler

@ KevinWheeler Damit das funktioniert, musst du es verwenden shell=True.
SethMMorton

38
@ KevinWheeler Sie sollten NICHT verwenden shell=True, für diesen Zweck wird Python mit os.path.expandvars geliefert . In Ihrem Fall können Sie schreiben : os.path.expandvars("$PATH"). @ SethMMorton bitte überdenken Sie Ihren Kommentar -> Warum nicht Shell = True verwenden
Murmel

blockiert block? Wenn ich also mehrere Befehle in einer forSchleife ausführen möchte, wie mache ich das, ohne dass mein Python-Skript blockiert wird? Die Ausgabe des Befehls ist mir egal, ich möchte nur viele davon ausführen.
Charlie Parker

4
Wenn Sie möchten , eine Liste erstellen mit den Parametern eines Befehls aus einer Liste , die mit verwendet werden kann , subprocesswenn shell=False, dann verwenden Sie shlex.splitfür eine einfache Möglichkeit , dies zu tun docs.python.org/2/library/shlex.html#shlex.split
Daniel F

2984

Hier ist eine Zusammenfassung der Möglichkeiten, externe Programme aufzurufen, sowie der Vor- und Nachteile der einzelnen Programme:

  1. os.system("some_command with args")Übergibt den Befehl und die Argumente an die Shell Ihres Systems. Dies ist hilfreich, da Sie auf diese Weise tatsächlich mehrere Befehle gleichzeitig ausführen und Pipes sowie eine Eingabe- / Ausgabeleitung einrichten können. Zum Beispiel:

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

Dies ist zwar praktisch, Sie müssen jedoch das Escapezeichen von Shell-Zeichen wie Leerzeichen usw. manuell behandeln. Auf diese Weise können Sie jedoch auch Befehle ausführen, bei denen es sich lediglich um Shell-Befehle und nicht um externe Programme handelt. Siehe die Dokumentation .

  1. stream = os.popen("some_command with args")wird das Gleiche tun, os.systemaußer dass es Ihnen ein dateiähnliches Objekt gibt, mit dem Sie auf die Standardeingabe / -ausgabe für diesen Prozess zugreifen können. Es gibt 3 andere Varianten von Popen, die alle die E / A etwas anders handhaben. Wenn Sie alles als Zeichenfolge übergeben, wird Ihr Befehl an die Shell übergeben. Wenn Sie sie als Liste übergeben, müssen Sie sich keine Sorgen machen, dass Sie irgendetwas entkommen. Siehe die Dokumentation .

  2. Die PopenKlasse des subprocessModuls. Dies ist als Ersatz für gedacht os.popen, hat aber den Nachteil, dass es aufgrund seiner Vollständigkeit etwas komplizierter ist. Zum Beispiel würden Sie sagen:

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

    anstatt:

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

    Es ist jedoch schön, alle Optionen in einer einheitlichen Klasse anstelle von 4 verschiedenen Popen-Funktionen zu haben. Siehe die Dokumentation .

  3. Die callFunktion aus dem subprocessModul. Dies ist im Grunde genau wie die PopenKlasse und akzeptiert alle gleichen Argumente, wartet jedoch einfach, bis der Befehl abgeschlossen ist und Sie den Rückkehrcode erhalten. Zum Beispiel:

    return_code = subprocess.call("echo Hello World", shell=True)  

    Siehe die Dokumentation .

  4. Wenn Sie mit Python 3.5 oder höher arbeiten, können Sie die neue subprocess.runFunktion verwenden, die der obigen sehr ähnlich ist, aber noch flexibler ist und ein CompletedProcessObjekt zurückgibt, wenn der Befehl die Ausführung beendet hat.

  5. Das OS-Modul verfügt auch über alle Fork / Exec / Spawn-Funktionen, die Sie in einem C-Programm haben würden, aber ich empfehle nicht, sie direkt zu verwenden.

Das subprocessModul sollte wahrscheinlich das sein, was Sie verwenden.

Beachten Sie schließlich, dass für alle Methoden, bei denen Sie den endgültigen Befehl übergeben, der von der Shell als Zeichenfolge ausgeführt werden soll, Sie dafür verantwortlich sind, ihn zu maskieren. Es gibt schwerwiegende Auswirkungen auf die Sicherheit, wenn einem Teil der übergebenen Zeichenfolge nicht vollständig vertraut werden kann. Zum Beispiel, wenn ein Benutzer einen Teil der Zeichenfolge eingibt. Wenn Sie sich nicht sicher 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, "meine Mutter hat mich nicht geliebt && rm -rf /", das das gesamte Dateisystem löschen könnte.


22
Schöne Antwort / Erklärung. Wie rechtfertigt diese Antwort Pythons Motto, wie in diesem Artikel beschrieben? fastcompany.com/3026446/… "Stilistisch gesehen haben Perl und Python unterschiedliche Philosophien. Perls bekannteste Mottos sind" Es gibt mehr als einen Weg, dies zu tun ". Python wurde entwickelt, um einen offensichtlichen Weg zu finden, wie es sein sollte." der andere Weg! In Perl kenne ich nur zwei Möglichkeiten, einen Befehl auszuführen - mit Back-Tick oder open.
Jean

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

4
Was man normalerweise wissen muss, ist, was mit STDOUT und STDERR des untergeordneten Prozesses gemacht wird, denn wenn sie unter bestimmten (recht häufigen) Bedingungen ignoriert werden, gibt der untergeordnete Prozess schließlich einen Systemaufruf aus, um in STDOUT zu schreiben (auch STDERR?). Dies würde den vom Betriebssystem für den Prozess bereitgestellten Ausgabepuffer überschreiten, und das Betriebssystem veranlasst ihn zu blockieren, bis ein Prozess aus diesem Puffer liest. subprocess.run(..)Was genau bedeutet mit den derzeit empfohlenen Methoden ? "Dies erfasst standardmäßig nicht stdout oder stderr." implizieren? Was ist mit subprocess.check_output(..)und STDERR?
Evgeni Sergeev

2
@Pitto ja, aber das wird vom Beispiel nicht ausgeführt. Beachten Sie die echovor der Zeichenfolge übergeben an Popen? So wird der volle Befehl sein echo my mama didnt love me && rm -rf /.
Chris Arndt

6
Dies ist wohl der falsche Weg. Die meisten Menschen brauchen nur subprocess.run()oder seine älteren Geschwister subprocess.check_call()et al. Für Fälle, in denen diese nicht ausreichen, siehe subprocess.Popen(). os.popen()sollte vielleicht gar nicht erwähnt werden oder auch nach "hacken Sie Ihren eigenen Fork / Exec / Spawn-Code" kommen.
Tripleee

358

Typische Implementierung:

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()

Sie können mit den stdoutDaten in der Pipe tun, was Sie wollen . Tatsächlich können Sie diese Parameter ( stdout=und stderr=) einfach weglassen und es wird sich so verhalten os.system().


44
.readlines()liest alle Zeilen auf einmal, dh es blockiert, bis der Unterprozess beendet wird (schließt sein Ende der Pipe). Um in Echtzeit zu lesen (wenn es keine Pufferprobleme gibt), können Sie:for line in iter(p.stdout.readline, ''): print line,
jfs

1
Könnten Sie näher erläutern, was Sie unter "wenn es keine Pufferprobleme gibt" verstehen? Wenn der Prozess definitiv blockiert, wird auch der Unterprozessaufruf blockiert. Das gleiche könnte auch mit meinem ursprünglichen Beispiel passieren. Was könnte sonst noch in Bezug auf die Pufferung passieren?
EmmEff

15
Der untergeordnete Prozess verwendet möglicherweise die Blockpufferung im nicht interaktiven Modus anstelle der Zeilenpufferung, sodass p.stdout.readline()(Hinweis: Nein sam Ende) keine Daten angezeigt werden, bis das untergeordnete Element seinen Puffer füllt. Wenn das Kind nicht viele Daten produziert, erfolgt die Ausgabe nicht in Echtzeit. Siehe den zweiten Grund in F: Warum nicht einfach eine Pipe (popen ()) verwenden? . Einige Problemumgehungen sind in dieser Antwort angegeben (pexpect, pty, stdbuf)
jfs

4
Das Pufferungsproblem ist nur wichtig, wenn Sie eine Ausgabe in Echtzeit wünschen und nicht für Ihren Code gelten, der nichts druckt, bis alle Daten empfangen wurden
jfs

3
Diese Antwort war für seine Zeit in Ordnung, aber wir sollten sie nicht mehr Popenfür einfache Aufgaben empfehlen . Dies spezifiziert auch unnötig shell=True. Versuchen Sie eine der subprocess.run()Antworten.
Tripleee

230

Einige Hinweise zum Trennen des untergeordneten Prozesses vom aufrufenden (Starten des untergeordneten Prozesses im Hintergrund).

Angenommen, Sie möchten eine lange Aufgabe über ein CGI-Skript starten. Das heißt, der untergeordnete Prozess sollte länger dauern als der Ausführungsprozess des CGI-Skripts.

Das klassische Beispiel aus der Dokumentation des Unterprozessmoduls lautet:

import subprocess
import sys

# Some code here

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

# Some more code here

Die Idee hier ist, dass Sie nicht in der Zeile 'Unterprozess aufrufen' warten möchten, bis die Datei longtask.py fertig ist. Es ist jedoch nicht klar, was nach der Zeile "hier etwas mehr Code" aus dem Beispiel passiert.

Meine Zielplattform war FreeBSD, aber die Entwicklung war unter Windows, so dass ich zuerst unter Windows mit dem Problem konfrontiert war.

Unter Windows (Windows XP) wird der übergeordnete Prozess erst beendet, wenn die Datei longtask.py ihre Arbeit beendet hat. Es ist nicht das, was Sie in einem CGI-Skript wollen. Das Problem ist nicht spezifisch für Python. In der PHP-Community sind die Probleme dieselben.

Die Lösung besteht darin, DETACHED_PROCESS zu übergeben Prozesserstellungsflag an die zugrunde liegende CreateProcess-Funktion in der Windows-API zu übergeben. Wenn Sie pywin32 installiert haben, können Sie das Flag aus dem win32process-Modul importieren. Andernfalls sollten Sie es selbst definieren:

DETACHED_PROCESS = 0x00000008

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

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

Unter FreeBSD haben wir ein weiteres Problem: Wenn der übergeordnete Prozess abgeschlossen ist, werden auch die untergeordneten Prozesse abgeschlossen. Und das ist auch nicht das, was Sie in einem CGI-Skript wollen. Einige Experimente zeigten, dass das Problem darin bestand, sys.stdout zu teilen. 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 auf anderen Plattformen nicht überprüft und kenne die Gründe für das Verhalten unter FreeBSD nicht. Wenn jemand weiß, teilen Sie bitte Ihre Ideen. Das Googeln beim Starten von Hintergrundprozessen in Python bringt noch kein Licht.


Ich bemerkte eine mögliche "Eigenart" bei der Entwicklung von py2exe-Apps in pydev + eclipse. Ich konnte feststellen, dass das Hauptskript nicht getrennt wurde, weil das Ausgabefenster von Eclipse nicht beendet wurde. Selbst wenn das Skript vollständig ausgeführt wird, wartet es immer noch auf die Rückgabe. Aber als ich versuchte, zu einer ausführbaren py2exe-Datei zu kompilieren, trat das erwartete Verhalten auf (führt die Prozesse als getrennt aus und wird dann beendet). Ich bin nicht sicher, aber der ausführbare Name ist nicht mehr in der Prozessliste. Dies funktioniert für alle Ansätze (os.system ("start *"), os.spawnl mit os.P_DETACH, Subprocs usw.)
maranas

1
Möglicherweise benötigen Sie auch das Flag CREATE_NEW_PROCESS_GROUP. Siehe Popen, der auf den untergeordneten Prozess wartet, selbst wenn das unmittelbare Kind beendet wurde
jfs

5
Folgendes ist falsch: "In Windows (Win XP) wird der übergeordnete Prozess erst beendet, wenn die Datei longtask.py ihre Arbeit beendet hat." Das übergeordnete Element wird normal beendet, aber das Konsolenfenster (Instanz conhost.exe) wird erst geschlossen, wenn der letzte angehängte Prozess beendet wird, und das untergeordnete Element hat möglicherweise die Konsole des übergeordneten Elements geerbt. Einstellung DETACHED_PROCESSin creationflagsvermeidet dies durch das Kind zu verhindern , vererben oder eine Konsole zu schaffen. Wenn Sie stattdessen eine neue Konsole möchten, verwenden Sie CREATE_NEW_CONSOLE(0x00000010).
Eryk Sun

1
Ich habe nicht gemeint, dass die Ausführung als getrennter Prozess falsch ist. Möglicherweise müssen Sie die Standardhandles jedoch auf Dateien, Pipes oder os.devnullweil einige Konsolenprogramme mit einem anderen Fehler beendet werden, festlegen. Erstellen Sie eine neue Konsole, wenn der untergeordnete Prozess gleichzeitig mit dem übergeordneten Prozess mit dem Benutzer interagieren soll. Es wäre verwirrend zu versuchen, beides in einem einzigen Fenster zu tun.
Eryk Sun

1
Gibt es keine betriebssystemunabhängige Möglichkeit, den Prozess im Hintergrund auszuführen?
Charlie Parker

152
import os
os.system("your command")

Beachten Sie, dass dies gefährlich ist, da der Befehl nicht bereinigt wird. Ich überlasse es Ihnen, bei Google nach der entsprechenden Dokumentation zu den Modulen 'os' und 'sys' zu suchen. Es gibt eine Reihe von Funktionen (exec * und spawn *), die ähnliche Aufgaben ausführen.


6
Keine Ahnung, was ich vor fast einem Jahrzehnt gemeint habe (überprüfen Sie das Datum!), Aber wenn ich raten müsste, würde es sein, dass keine Validierung durchgeführt wird.
Nimish

1
Dies sollte nun subprocessals etwas vielseitigere und tragbarere Lösung gelten. Das Ausführen externer Befehle ist natürlich von Natur aus nicht portierbar (Sie müssen sicherstellen, dass der Befehl in jeder Architektur verfügbar ist, die Sie unterstützen müssen), und das Übergeben von Benutzereingaben als externer Befehl ist von Natur aus unsicher.
Tripleee

1
Beachten Sie den Zeitstempel für diesen Typen: Die "richtige" Antwort hat das 40-fache der Stimmen und ist die Antwort Nr. 1.
Nimish

Die einzige Lösung, die für mich beim Ausführen von NodeJS-Inhalten funktioniert hat.
Nikolay Shindarov

148

Ich würde empfehlen , das mit Subprozess Modul statt os.system , weil es für Sie nicht Shell zu entkommen und ist daher viel sicherer.

subprocess.call(['ping', 'localhost'])

Wenn Sie wollen eine Liste aus einem Befehl mit Parametern erstellen , eine Liste , die mit verwendet werden , subprocesswenn shell=False, dann verwenden Sie shlex.splitfür eine einfache Möglichkeit , dies zu tun docs.python.org/2/library/shlex.html#shlex.split ( Dies ist der empfohlene Weg gemäß den Dokumenten docs.python.org/2/library/subprocess.html#popen-constructor )
Daniel F

6
Dies ist falsch: " Es entweicht für Sie und ist daher viel sicherer. " Der Unterprozess führt kein Shell-Escape durch. Der Unterprozess leitet Ihren Befehl nicht durch die Shell, sodass kein Shell-Escape erforderlich ist.
Lie Ryan

144
import os
cmd = 'ls -al'
os.system(cmd)

Wenn Sie die Ergebnisse des Befehls zurückgeben möchten, können Sie verwenden os.popen. Dies ist jedoch seit Version 2.6 zugunsten des Unterprozessmoduls veraltet , was andere Antworten gut abgedeckt haben.


10
popen ist zugunsten des Teilprozesses veraltet .
Fox Wilson

Sie können Ihr Ergebnis auch mit dem Aufruf von os.system speichern, da es wie die UNIX-Shell selbst funktioniert, wie zum Beispiel os.system ('ls -l> test2.txt')
Stefan Gruenwald

97

Es gibt viele verschiedene Bibliotheken, mit denen Sie externe Befehle mit Python aufrufen können. Für jede Bibliothek habe ich eine Beschreibung gegeben und ein Beispiel für das Aufrufen eines externen Befehls gezeigt. Der Befehl, den ich als Beispiel verwendet habe, lautet ls -l(alle Dateien auflisten). Wenn Sie mehr über eine der Bibliotheken erfahren möchten, die ich aufgelistet und die Dokumentation für jede Bibliothek verknüpft habe.

Quellen:

Dies sind alle Bibliotheken:

Hoffentlich hilft Ihnen dies bei der Entscheidung, welche Bibliothek Sie verwenden möchten :)

Unterprozess

Mit dem Unterprozess können Sie externe Befehle aufrufen und diese mit ihren Eingabe- / Ausgabe- / Fehlerleitungen (stdin, stdout und stderr) verbinden. Unterprozess ist die Standardauswahl zum Ausführen von Befehlen, aber manchmal sind andere Module besser.

subprocess.run(["ls", "-l"]) # Run command
subprocess.run(["ls", "-l"], stdout=subprocess.PIPE) # This will run the command and return any output
subprocess.run(shlex.split("ls -l")) # You can also use the shlex library to split the command

os

os wird für "betriebssystemabhängige Funktionalität" verwendet. Es kann auch verwendet werden, um externe Befehle mit os.systemund aufzurufen os.popen(Hinweis: Es gibt auch einen subprocess.popen). os führt immer die Shell aus und ist eine einfache Alternative für Leute, die es nicht brauchen oder nicht wissen, wie man es benutzt subprocess.run.

os.system("ls -l") # run command
os.popen("ls -l").read() # This will run the command and return any output

Sch

sh ist eine Unterprozessschnittstelle, mit der Sie Programme aufrufen können, als wären sie Funktionen. Dies ist nützlich, wenn Sie einen Befehl mehrmals ausführen möchten.

sh.ls("-l") # Run command normally
ls_cmd = sh.Command("ls") # Save command as a variable
ls_cmd() # Run command as if it were a function

Plumbum

plumbum ist eine Bibliothek für "script-like" Python-Programme. Sie können Programme wie Funktionen wie in aufrufen sh. Plumbum ist nützlich, wenn Sie eine Pipeline ohne Shell ausführen möchten.

ls_cmd = plumbum.local("ls -l") # get command
ls_cmd() # run command

pexpect

Mit pexpect können Sie untergeordnete Anwendungen erzeugen, steuern und Muster in ihrer Ausgabe finden. Dies ist eine bessere Alternative zum Unterprozess für Befehle, die unter Unix eine tty erwarten.

pexpect.run("ls -l") # Run command as normal
child = pexpect.spawn('scp foo user@example.com:.') # Spawns child application
child.expect('Password:') # When this is the output
child.sendline('mypassword')

Stoff

Fabric ist eine Python 2.5- und 2.7-Bibliothek. Hier können Sie lokale und Remote-Shell-Befehle ausführen. Fabric ist eine einfache Alternative zum Ausführen von Befehlen in einer sicheren Shell (SSH).

fabric.operations.local('ls -l') # Run command as normal
fabric.operations.local('ls -l', capture = True) # Run command and receive output

Gesandte

Gesandter ist als "Unterprozess für den Menschen" bekannt. Es wird als Convenience-Wrapper um das subprocessModul verwendet.

r = envoy.run("ls -l") # Run command
r.std_out # get output

Befehle

commandsenthält Wrapper-Funktionen für os.popen, wurde jedoch aus Python 3 entfernt, da dies subprocesseine bessere Alternative darstellt.

Die Bearbeitung basierte auf dem Kommentar von JF Sebastian.


74

Ich benutze immer fabricfür diese Dinge wie:

from fabric.operations import local
result = local('ls', capture=True)
print "Content:/n%s" % (result, )

Dies scheint jedoch ein gutes Werkzeug zu sein: sh(Python-Subprozessschnittstelle) .

Schauen Sie sich ein Beispiel an:

from sh import vgdisplay
print vgdisplay()
print vgdisplay('-v')
print vgdisplay(v=True)

73

Überprüfen Sie auch die Python-Bibliothek "pexpect".

Es ermöglicht die interaktive Steuerung externer Programme / Befehle, sogar von SSH, FTP, Telnet usw. Sie können einfach Folgendes eingeben:

child = pexpect.spawn('ftp 192.168.0.24')

child.expect('(?i)name .*: ')

child.sendline('anonymous')

child.expect('(?i)password')

70

Mit der Standardbibliothek

Verwenden Sie das Unterprozessmodul (Python 3):

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

Dies ist der empfohlene Standardweg. Kompliziertere Aufgaben (Pipes, Ausgabe, Eingabe usw.) können jedoch mühsam zu konstruieren und zu schreiben sein.

Hinweis zur Python-Version: Wenn Sie noch Python 2 verwenden, funktioniert subprocess.call auf ähnliche Weise.

ProTip: shlex.split kann Ihnen helfen, den Befehl für und andere Funktionen zu analysieren run, falls Sie diese nicht in Form von Listen bereitstellen möchten (oder können!).callsubprocess

import shlex
import subprocess
subprocess.run(shlex.split('ls -l'))

Mit externen Abhängigkeiten

Wenn Ihnen externe Abhängigkeiten nichts ausmachen, verwenden Sie plumbum :

from plumbum.cmd import ifconfig
print(ifconfig['wlan0']())

Es ist die beste subprocessVerpackung. Es ist plattformübergreifend, dh es funktioniert sowohl auf Windows- als auch auf Unix-ähnlichen Systemen. Installieren von pip install plumbum.

Eine weitere beliebte Bibliothek ist sh :

from sh import ifconfig
print(ifconfig('wlan0'))

Die shWindows-Unterstützung wurde jedoch eingestellt, sodass sie nicht mehr so ​​beeindruckend ist wie früher. Installieren von pip install sh.


69

Wenn Sie die Ausgabe des Befehls müssen Sie anrufen, dann können Sie verwenden subprocess.check_output (Python 2.7+).

>>> subprocess.check_output(["ls", "-l", "/dev/null"])
'crw-rw-rw- 1 root root 1, 3 Oct 18  2007 /dev/null\n'

Beachten Sie auch den Shell- Parameter.

Wenn dies Trueder Fall ist , wird der angegebene Befehl über die Shell ausgeführt. Dies kann nützlich sein, wenn Sie Python hauptsächlich für den erweiterten Steuerungsfluss verwenden, den es über die meisten System-Shells bietet, und dennoch bequemen Zugriff auf andere Shell-Funktionen wie Shell-Pipes, Platzhalter für Dateinamen, Erweiterung von Umgebungsvariablen und Erweiterung von ~ auf das Heim eines Benutzers wünschen Verzeichnis. Beachten Sie jedoch, dass Python selbst bietet Implementierungen von vielen schalenartigen Eigenschaften (insbesondere glob, fnmatch, os.walk(), os.path.expandvars(), os.path.expanduser(), und shutil).


1
Beachten Sie, check_outputdass eine Liste anstelle einer Zeichenfolge erforderlich ist. Wenn Sie sich nicht auf Anführungszeichen verlassen, um Ihren Anruf gültig zu machen, ist dies am einfachsten und am besten lesbar subprocess.check_output("ls -l /dev/null".split()).
Bruno Bronosky

56

So führe ich meine Befehle aus. Dieser Code enthält alles, was Sie brauchen

from subprocess import Popen, PIPE
cmd = "ls -l ~/"
p = Popen(cmd , shell=True, stdout=PIPE, stderr=PIPE)
out, err = p.communicate()
print "Return code: ", p.returncode
print out.rstrip(), err.rstrip()

3
Ich denke, es ist akzeptabel für hartcodierte Befehle, wenn es die Lesbarkeit erhöht.
Adam Matan

54

Aktualisieren:

subprocess.runist der empfohlene Ansatz ab Python 3.5, wenn Ihr Code nicht mit früheren Python-Versionen kompatibel sein muss. Es ist konsistenter und bietet eine ähnliche Benutzerfreundlichkeit wie Envoy. (Rohrleitungen sind jedoch nicht so einfach. In dieser Frage erfahren Sie, wie .)

Hier einige Beispiele aus der Dokumentation .

Führen Sie einen Prozess aus:

>>> subprocess.run(["ls", "-l"])  # Doesn't capture output
CompletedProcess(args=['ls', '-l'], returncode=0)

Bei fehlgeschlagenem Lauf erhöhen:

>>> subprocess.run("exit 1", shell=True, check=True)
Traceback (most recent call last):
  ...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1

Ausgabe erfassen:

>>> subprocess.run(["ls", "-l", "/dev/null"], stdout=subprocess.PIPE)
CompletedProcess(args=['ls', '-l', '/dev/null'], returncode=0,
stdout=b'crw-rw-rw- 1 root root 1, 3 Jan 23 16:23 /dev/null\n')

Ursprüngliche Antwort:

Ich empfehle Envoy zu versuchen . Es ist ein Wrapper für Unterprozesse, der wiederum die älteren Module und Funktionen ersetzen soll . Gesandter ist ein Unterprozess für Menschen.

Anwendungsbeispiel aus der README :

>>> r = envoy.run('git config', data='data to pipe in', timeout=2)

>>> r.status_code
129
>>> r.std_out
'usage: git config [options]'
>>> r.std_err
''

Pipe Zeug auch herum:

>>> r = envoy.run('uptime | pbcopy')

>>> r.command
'pbcopy'
>>> r.status_code
0

>>> r.history
[<Response 'uptime'>]


36

os.systemist in Ordnung, aber irgendwie veraltet. Es ist auch nicht sehr sicher. Versuchen Sie es stattdessen subprocess. subprocessruft sh nicht direkt an und ist daher sicherer als os.system.

Weitere Informationen erhalten Sie hier .


2
Ich stimme zwar der allgemeinen Empfehlung zu, subprocessbehebe jedoch nicht alle Sicherheitsprobleme und habe einige lästige Probleme.
Tripleee

36

Aufrufen eines externen Befehls in Python

Einfach, verwenden subprocess.run, was ein CompletedProcessObjekt zurückgibt :

>>> import subprocess
>>> completed_process = subprocess.run('python --version')
Python 3.6.1 :: Anaconda 4.4.0 (64-bit)
>>> completed_process
CompletedProcess(args='python --version', returncode=0)

Warum?

Ab Python 3.5 wird in der Dokumentation subprocess.run empfohlen :

Der empfohlene Ansatz zum Aufrufen von Unterprozessen besteht darin, die Funktion run () für alle Anwendungsfälle zu verwenden, die behandelt werden können. Für fortgeschrittenere Anwendungsfälle kann die zugrunde liegende Popen-Schnittstelle direkt verwendet werden.

Hier ist ein Beispiel für die einfachste Verwendung - und es funktioniert genau so, wie es verlangt wird:

>>> import subprocess
>>> completed_process = subprocess.run('python --version')
Python 3.6.1 :: Anaconda 4.4.0 (64-bit)
>>> completed_process
CompletedProcess(args='python --version', returncode=0)

runWartet, bis der Befehl erfolgreich abgeschlossen wurde, und gibt dann ein CompletedProcessObjekt zurück. Es kann stattdessen erhöhen TimeoutExpired(wenn Sie ihm ein timeout=Argument geben) oder CalledProcessError(wenn es fehlschlägt und Sie bestehen check=True).

Wie Sie dem obigen Beispiel entnehmen können, werden stdout und stderr standardmäßig an Ihr eigenes stdout und stderr weitergeleitet.

Wir können das zurückgegebene Objekt untersuchen und den Befehl und den Rückkehrcode sehen:

>>> completed_process.args
'python --version'
>>> completed_process.returncode
0

Ausgabe erfassen

Wenn Sie die Ausgabe erfassen möchten, können Sie subprocess.PIPEan die entsprechende übergeben stderroder stdout:

>>> cp = subprocess.run('python --version', 
                        stderr=subprocess.PIPE, 
                        stdout=subprocess.PIPE)
>>> cp.stderr
b'Python 3.6.1 :: Anaconda 4.4.0 (64-bit)\r\n'
>>> cp.stdout
b''

(Ich finde es interessant und etwas eingängig, dass die Versionsinformationen auf stderr anstatt auf stdout gesetzt werden.)

Übergeben Sie eine Befehlsliste

Man könnte leicht von der manuellen Bereitstellung einer Befehlszeichenfolge (wie in der Frage vorgeschlagen) zur Bereitstellung einer programmgesteuert erstellten Zeichenfolge übergehen. Erstellen Sie keine Zeichenfolgen programmgesteuert. Dies ist ein potenzielles Sicherheitsproblem. Es ist besser anzunehmen, dass Sie der Eingabe nicht vertrauen.

>>> import textwrap
>>> args = ['python', textwrap.__file__]
>>> cp = subprocess.run(args, stdout=subprocess.PIPE)
>>> cp.stdout
b'Hello there.\r\n  This is indented.\r\n'

Beachten Sie, dass nur argspositionell übergeben werden sollte.

Vollständige Unterschrift

Hier ist die tatsächliche Signatur in der Quelle und wie gezeigt durch help(run):

def run(*popenargs, input=None, timeout=None, check=False, **kwargs):

Die popenargsund kwargswerden dem PopenKonstruktor gegeben. inputkann eine Zeichenfolge von Bytes sein (oder Unicode, wenn Codierung angegeben ist oder universal_newlines=True), die an das stdin des Unterprozesses weitergeleitet wird.

Die Dokumentation beschreibt timeout=und check=Truebesser als ich könnte:

Das Timeout-Argument wird an Popen.communicate () übergeben. Wenn das Zeitlimit abläuft, wird der untergeordnete Prozess abgebrochen und gewartet. Die TimeoutExpired-Ausnahme wird erneut ausgelöst, nachdem der untergeordnete Prozess beendet wurde.

Wenn die Prüfung wahr ist und der Prozess mit einem Exit-Code ungleich Null beendet wird, wird eine CalledProcessError-Ausnahme ausgelöst. Attribute dieser Ausnahme enthalten die Argumente, den Exit-Code sowie stdout und stderr, wenn sie erfasst wurden.

und dieses Beispiel für check=Trueist besser als eines, das ich mir einfallen lassen könnte:

>>> subprocess.run("exit 1", shell=True, check=True)
Traceback (most recent call last):
  ...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1

Erweiterte Signatur

Hier ist eine erweiterte Signatur, wie in der Dokumentation angegeben:

subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, 
shell=False, cwd=None, timeout=None, check=False, encoding=None, 
errors=None)

Beachten Sie, dass dies darauf hinweist, dass nur die Args-Liste positionell übergeben werden sollte. Übergeben Sie also die verbleibenden Argumente als Schlüsselwortargumente.

Popen

Wann Popenstattdessen verwenden? Ich würde mich bemühen, einen Anwendungsfall allein aufgrund der Argumente zu finden. Die direkte Verwendung von Popenwürde Ihnen jedoch Zugriff auf seine Methoden gewähren, einschließlich poll'send_signal', 'terminate' und 'wait'.

Hier ist die PopenUnterschrift wie in der Quelle angegeben . Ich denke, dies ist die genaueste Kapselung der Informationen (im Gegensatz zu help(Popen)):

def __init__(self, args, bufsize=-1, executable=None,
             stdin=None, stdout=None, stderr=None,
             preexec_fn=None, close_fds=_PLATFORM_DEFAULT_CLOSE_FDS,
             shell=False, cwd=None, env=None, universal_newlines=False,
             startupinfo=None, creationflags=0,
             restore_signals=True, start_new_session=False,
             pass_fds=(), *, encoding=None, errors=None):

Informativer ist jedoch die PopenDokumentation :

subprocess.Popen(args, bufsize=-1, executable=None, stdin=None,
                 stdout=None, stderr=None, preexec_fn=None, close_fds=True,
                 shell=False, cwd=None, env=None, universal_newlines=False,
                 startupinfo=None, creationflags=0, restore_signals=True,
                 start_new_session=False, pass_fds=(), *, encoding=None, errors=None)

Führen Sie ein untergeordnetes Programm in einem neuen Prozess aus. Unter POSIX verwendet die Klasse das Verhalten os.execvp (), um das untergeordnete Programm auszuführen. Unter Windows verwendet die Klasse die Windows-Funktion CreateProcess (). Die Argumente an Popen lauten wie folgt.

Das Verständnis der verbleibenden Dokumentation Popenwird dem Leser als Übung überlassen.


Ein einfaches Beispiel für die bidirektionale
James Hirschorn

Das erste Beispiel sollte wohl haben shell=True den Befehl als Liste oder (noch besser) übergeben.
Tripleee

33

Es gibt auch Plumbum

>>> from plumbum import local
>>> ls = local["ls"]
>>> ls
LocalCommand(<LocalPath /bin/ls>)
>>> ls()
u'build.py\ndist\ndocs\nLICENSE\nplumbum\nREADME.rst\nsetup.py\ntests\ntodo.txt\n'
>>> notepad = local["c:\\windows\\notepad.exe"]
>>> notepad()                                   # Notepad window pops up
u''                                             # Notepad window is closed by user, command returns

28

Verwenden:

import os

cmd = 'ls -al'

os.system(cmd)

os - Dieses Modul bietet eine tragbare Möglichkeit, betriebssystemabhängige Funktionen zu verwenden.

Für die weiteren osFunktionen finden Sie hier die Dokumentation.


2
es ist auch veraltet. Verwenden Sie den Unterprozess
Corey Goldberg

28

So einfach kann es sein:

import os
cmd = "your command"
os.system(cmd)

1
Dies weist nicht auf die Nachteile hin, die in PEP-324 ausführlicher erläutert werden . In der Dokumentation wird os.systemausdrücklich empfohlen, dies zugunsten von zu vermeiden subprocess.
Tripleee

25

Ich mag shell_command wegen seiner Einfachheit. Es basiert auf dem Unterprozessmodul.

Hier ist ein Beispiel aus der Dokumentation:

>>> from shell_command import shell_call
>>> shell_call("ls *.py")
setup.py  shell_command.py  test_shell_command.py
0
>>> shell_call("ls -l *.py")
-rw-r--r-- 1 ncoghlan ncoghlan  391 2011-12-11 12:07 setup.py
-rw-r--r-- 1 ncoghlan ncoghlan 7855 2011-12-11 16:16 shell_command.py
-rwxr-xr-x 1 ncoghlan ncoghlan 8463 2011-12-11 16:17 test_shell_command.py
0

24

Es gibt hier einen weiteren Unterschied, der zuvor nicht erwähnt wurde.

subprocess.Popenführt den <Befehl> als Unterprozess aus. In meinem Fall muss ich die Datei <a> ausführen, die mit einem anderen Programm <b> kommunizieren muss.

Ich habe versucht, einen Unterprozess durchzuführen, und die Ausführung war erfolgreich. <b> konnte jedoch nicht mit <a> kommunizieren. Alles ist normal, wenn ich beide vom Terminal aus starte.

Noch eines: (HINWEIS: kwrite verhält sich anders als andere Anwendungen. Wenn Sie das Folgende mit Firefox versuchen, sind die Ergebnisse nicht dieselben.)

Wenn Sie es versuchen os.system("kwrite"), friert der Programmfluss ein, bis der Benutzer kwrite schließt. Um das zu überwinden, habe ich stattdessen versuchtos.system(konsole -e kwrite) . Dieses Mal floss das Programm weiter, aber kwrite wurde zum Unterprozess der Konsole.

Jeder führt das kwrite nicht als Unterprozess aus (dh im Systemmonitor muss es am linken Rand des Baums angezeigt werden).


1
Was meinst du mit "Jeder führt den Kwrite aus, der kein Unterprozess ist" ?
Peter Mortensen

23

os.systemerlaubt Ihnen nicht, Ergebnisse zu speichern. Wenn Sie also Ergebnisse in einer Liste oder etwas anderem speichern möchten, subprocess.callfunktioniert a.


22

subprocess.check_callist praktisch, wenn Sie keine Rückgabewerte testen möchten. Bei jedem Fehler wird eine Ausnahme ausgelöst.


22

Ich neige dazu verwenden subprocess zusammen mit shlex (zu handhaben von Strings in Anführungszeichen zu entkommen):

>>> import subprocess, shlex
>>> command = 'ls -l "/your/path/with spaces/"'
>>> call_params = shlex.split(command)
>>> print call_params
["ls", "-l", "/your/path/with spaces/"]
>>> subprocess.call(call_params)

17

Schamloser Plug, ich habe eine Bibliothek dafür geschrieben: P https://github.com/houqp/shell.py

Es ist im Grunde ein Wrapper für Popen und Shlex für jetzt. Es werden auch Piping-Befehle unterstützt, sodass Sie Befehle in Python einfacher verketten können. So können Sie Dinge tun wie:

ex('echo hello shell.py') | "awk '{print $2}'"

16

In Windows können Sie nur das Import - subprocessModul und externe Befehle ausgeführt durch den Aufruf subprocess.Popen(), subprocess.Popen().communicate()und subprocess.Popen().wait()wie unten:

# Python script to run a command line
import subprocess

def execute(cmd):
    """
        Purpose  : To execute a command and return exit status
        Argument : cmd - command to execute
        Return   : exit_code
    """
    process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    (result, error) = process.communicate()

    rc = process.wait()

    if rc != 0:
        print "Error: failed to execute command:", cmd
        print error
    return result
# def

command = "tasklist | grep python"
print "This process detail: \n", execute(command)

Ausgabe:

This process detail:
python.exe                     604 RDP-Tcp#0                  4      5,660 K

15

Wenn Sie unter Linux einen externen Befehl aufrufen möchten, der unabhängig ausgeführt wird (der nach Beendigung des Python-Skripts weiter ausgeführt wird), können Sie eine einfache Warteschlange als Task-Spooler oder als at verwenden Befehl verwenden

Ein Beispiel mit Task-Spooler:

import os
os.system('ts <your-command>')

Hinweise zum Task-Spooler ( ts):

  1. Sie können die Anzahl der gleichzeitig auszuführenden Prozesse ("Slots") festlegen mit:

    ts -S <number-of-slots>

  2. Für die Installation sind tskeine Administratorrechte erforderlich. Sie können es einfach herunterladen und aus dem Quellcode kompilieren make, es Ihrem Pfad hinzufügen und fertig.


1
tsist in keiner mir bekannten Distribution Standard, obwohl der Zeiger auf atleicht nützlich ist. Sie sollten wahrscheinlich auch erwähnen batch. Wie überall sollte in der os.system()Empfehlung wahrscheinlich zumindest erwähnt werden, dass subprocesses sich um den empfohlenen Ersatz handelt.
Tripleee

15

Sie können Popen verwenden und anschließend den Status der Prozedur überprüfen:

from subprocess import Popen

proc = Popen(['ls', '-l'])
if proc.poll() is None:
    proc.kill()

Check out subprocess.Popen .


15

So rufen Sie die Netzwerk-ID vom OpenStack Neutron ab :

#!/usr/bin/python
import os
netid = "nova net-list | awk '/ External / { print $2 }'"
temp = os.popen(netid).read()  /* Here temp also contains new line (\n) */
networkId = temp.rstrip()
print(networkId)

Ausgabe der Nova-Netzliste

+--------------------------------------+------------+------+
| ID                                   | Label      | CIDR |
+--------------------------------------+------------+------+
| 431c9014-5b5d-4b51-a357-66020ffbb123 | test1      | None |
| 27a74fcd-37c0-4789-9414-9531b7e3f126 | External   | None |
| 5a2712e9-70dc-4b0e-9281-17e02f4684c9 | management | None |
| 7aa697f5-0e60-4c15-b4cc-9cb659698512 | Internal   | None |
+--------------------------------------+------------+------+

Ausgabe von print (NetworkID)

27a74fcd-37c0-4789-9414-9531b7e3f126

Sie sollten es os.popen()2016 nicht empfehlen . Das Awk-Skript kann leicht durch nativen Python-Code ersetzt werden.
Tripleee
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.