Wie ruft man einen externen Befehl (als hätte ich ihn an der Unix-Shell oder an der Windows-Eingabeaufforderung eingegeben) in einem Python-Skript auf?
Wie ruft man einen externen Befehl (als hätte ich ihn an der Unix-Shell oder an der Windows-Eingabeaufforderung eingegeben) in einem Python-Skript auf?
Antworten:
Schauen Sie sich das Unterprozessmodul in der Standardbibliothek an:
import subprocess
subprocess.run(["ls", "-l"])
Der Vorteil subprocess
gegenüber system
ist , dass es flexibler ist (Sie das bekommen kann stdout
, stderr
die „echten“ Statuscode, eine bessere Fehlerbehandlung, etc ...).
In der offiziellen Dokumentation wird das subprocess
Modul gegenüber der Alternative empfohlen os.system()
:
Das
subprocess
Modul 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 subprocess
Dokumentation enthält möglicherweise einige hilfreiche Rezepte.
Verwenden Sie für Versionen von Python vor 3.5 call
:
import subprocess
subprocess.call(["ls", "-l"])
shell=True
.
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
for
Schleife 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.
subprocess
wenn shell=False
, dann verwenden Sie shlex.split
für eine einfache Möglichkeit , dies zu tun docs.python.org/2/library/shlex.html#shlex.split
Hier ist eine Zusammenfassung der Möglichkeiten, externe Programme aufzurufen, sowie der Vor- und Nachteile der einzelnen Programme:
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 .
stream = os.popen("some_command with args")
wird das Gleiche tun, os.system
auß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 .
Die Popen
Klasse des subprocess
Moduls. 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 .
Die call
Funktion aus dem subprocess
Modul. Dies ist im Grunde genau wie die Popen
Klasse 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 .
Wenn Sie mit Python 3.5 oder höher arbeiten, können Sie die neue subprocess.run
Funktion verwenden, die der obigen sehr ähnlich ist, aber noch flexibler ist und ein CompletedProcess
Objekt zurückgibt, wenn der Befehl die Ausführung beendet hat.
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 subprocess
Modul 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.
open
.
subprocess.run()
. docs.python.org/3.5/library/subprocess.html#subprocess.run
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?
echo
vor der Zeichenfolge übergeben an Popen
? So wird der volle Befehl sein echo my mama didnt love me && rm -rf /
.
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.
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 stdout
Daten 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()
.
.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,
p.stdout.readline()
(Hinweis: Nein s
am 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)
Popen
für einfache Aufgaben empfehlen . Dies spezifiziert auch unnötig shell=True
. Versuchen Sie eine der subprocess.run()
Antworten.
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.
DETACHED_PROCESS
in creationflags
vermeidet 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).
os.devnull
weil 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.
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.
subprocess
als 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.
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'])
subprocess
wenn shell=False
, dann verwenden Sie shlex.split
fü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 )
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.
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.system
und 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 subprocess
Modul verwendet.
r = envoy.run("ls -l") # Run command
r.std_out # get output
Befehle
commands
enthält Wrapper-Funktionen für os.popen
, wurde jedoch aus Python 3 entfernt, da dies subprocess
eine bessere Alternative darstellt.
Die Bearbeitung basierte auf dem Kommentar von JF Sebastian.
Ich benutze immer fabric
fü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)
Ü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')
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!).call
subprocess
import shlex
import subprocess
subprocess.run(shlex.split('ls -l'))
Wenn Ihnen externe Abhängigkeiten nichts ausmachen, verwenden Sie plumbum :
from plumbum.cmd import ifconfig
print(ifconfig['wlan0']())
Es ist die beste subprocess
Verpackung. 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 sh
Windows-Unterstützung wurde jedoch eingestellt, sodass sie nicht mehr so beeindruckend ist wie früher. Installieren von pip install sh
.
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
True
der 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 (insbesondereglob
,fnmatch
,os.walk()
,os.path.expandvars()
,os.path.expanduser()
, undshutil
).
check_output
dass 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())
.
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()
subprocess.run
ist 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')
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'>]
Verwenden subprocess .
... oder für einen sehr einfachen Befehl:
import os
os.system('cat testfile')
os.system
ist in Ordnung, aber irgendwie veraltet. Es ist auch nicht sehr sicher. Versuchen Sie es stattdessen subprocess
. subprocess
ruft sh nicht direkt an und ist daher sicherer als os.system
.
Weitere Informationen erhalten Sie hier .
subprocess
behebe jedoch nicht alle Sicherheitsprobleme und habe einige lästige Probleme.
Aufrufen eines externen Befehls in Python
Einfach, verwenden subprocess.run
, was ein CompletedProcess
Objekt 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)
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)
run
Wartet, bis der Befehl erfolgreich abgeschlossen wurde, und gibt dann ein CompletedProcess
Objekt 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
Wenn Sie die Ausgabe erfassen möchten, können Sie subprocess.PIPE
an die entsprechende übergeben stderr
oder 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.)
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 args
positionell übergeben werden sollte.
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 popenargs
und kwargs
werden dem Popen
Konstruktor gegeben. input
kann 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=True
besser 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=True
ist 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
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.
Wann Popen
stattdessen verwenden? Ich würde mich bemühen, einen Anwendungsfall allein aufgrund der Argumente zu finden. Die direkte Verwendung von Popen
würde Ihnen jedoch Zugriff auf seine Methoden gewähren, einschließlich poll
'send_signal', 'terminate' und 'wait'.
Hier ist die Popen
Unterschrift 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 Popen
Dokumentation :
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 Popen
wird dem Leser als Übung überlassen.
shell=True
den Befehl als Liste oder (noch besser) übergeben.
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
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 os
Funktionen finden Sie hier die Dokumentation.
So einfach kann es sein:
import os
cmd = "your command"
os.system(cmd)
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
Es gibt hier einen weiteren Unterschied, der zuvor nicht erwähnt wurde.
subprocess.Popen
fü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).
os.system
erlaubt Ihnen nicht, Ergebnisse zu speichern. Wenn Sie also Ergebnisse in einer Liste oder etwas anderem speichern möchten, subprocess.call
funktioniert a.
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)
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}'"
In Windows können Sie nur das Import - subprocess
Modul 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
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
):
Sie können die Anzahl der gleichzeitig auszuführenden Prozesse ("Slots") festlegen mit:
ts -S <number-of-slots>
Für die Installation sind ts
keine Administratorrechte erforderlich. Sie können es einfach herunterladen und aus dem Quellcode kompilieren make
, es Ihrem Pfad hinzufügen und fertig.
ts
ist in keiner mir bekannten Distribution Standard, obwohl der Zeiger auf at
leicht nützlich ist. Sie sollten wahrscheinlich auch erwähnen batch
. Wie überall sollte in der os.system()
Empfehlung wahrscheinlich zumindest erwähnt werden, dass subprocess
es sich um den empfohlenen Ersatz handelt.
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 .
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
os.popen()
2016 nicht empfehlen . Das Awk-Skript kann leicht durch nativen Python-Code ersetzt werden.
echo $PATH
indem ich verwendet habecall(["echo", "$PATH"])
, aber es hat nur die Literalzeichenfolge wiedergegeben,$PATH
anstatt 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.