Wie kann ich einen externen Befehl aus einem Python-Skript heraus aufrufen (als hätte ich ihn an der Unix-Shell oder der Windows-Befehlszeile eingegeben)?
Schauen Sie sich das Subprozess-Modul in der Standardbibliothek an:
import subprocess
subprocess.run(["ls", "-l"])
Der Vorteil von subprozess gegenüber system ist, dass es flexibler ist (Sie können stdout, stderr, den "echten" Statuscode, bessere Fehlerbehandlung usw. erhalten).
Die offizielle Dokumentation empfiehlt das subprocess -Modul über das alternative os.system ():
Das subprocess -Modul bietet leistungsfähigere Funktionen, um neue Prozesse zu starten und ihre Ergebnisse abzurufen. Die Verwendung dieses Moduls ist der Verwendung dieser Funktion [
os.system()
] vorzuziehen.
Der Abschnitt " Ersetzen älterer Funktionen durch das Subprozess-Modul " in der Dokumentation subprocess enthält möglicherweise hilfreiche Rezepte.
Hier finden Sie eine Zusammenfassung der Möglichkeiten, externe Programme aufzurufen, sowie deren Vor- und Nachteile:
os.system("some_command with args")
übergibt den Befehl und die Argumente an die Shell Ihres Systems. Das ist schön, weil Sie auf diese Weise tatsächlich mehrere Befehle gleichzeitig ausführen und Pipes und Eingabe/Ausgabe-Umleitungen einrichten können. Zum Beispiel:
os.system("some_command < input_file | another_command > output_file")
Das ist zwar praktisch, Sie müssen jedoch manuell mit dem Escape-Verfahren von Shell-Zeichen wie Leerzeichen usw. umgehen. Auf der anderen Seite können Sie auch Befehle ausführen, die einfach Shell-Befehle und keine externen Programme sind. Siehe die Dokumentation .
stream = os.popen("some_command with args")
wird dasselbe tun wie os.system
, außer dass Sie ein dateiähnliches Objekt erhalten, mit dem Sie auf die Standardein-/ausgabe für diesen Prozess zugreifen können. Es gibt 3 weitere Varianten von popen, die alle mit der E/A etwas anders umgehen. Wenn Sie alles als String übergeben, wird Ihr Befehl an die Shell übergeben. Wenn Sie sie als Liste übergeben, müssen Sie sich keine Sorgen darüber machen, dass irgendetwas entkommt. Siehe die Dokumentation .
Die Popen
-Klasse des subprocess
-Moduls. Dies ist als Ersatz für os.popen
gedacht, hat jedoch den Nachteil, dass es aufgrund seiner umfassenden Eigenschaften 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()
aber es ist schön, alle Optionen in einer einheitlichen Klasse zu haben, anstatt 4 verschiedene Popen-Funktionen. Siehe die Dokumentation .
Die call
-Funktion aus dem subprocess
-Modul. Dies ist im Grunde genauso wie die Popen
-Klasse und nimmt alle gleichen Argumente an. Sie wartet jedoch einfach, bis der Befehl abgeschlossen ist, und gibt den Rückkehrcode zurück. Zum Beispiel:
return_code = subprocess.call("echo Hello World", Shell=True)
Siehe die Dokumentation .
Wenn Sie Python 3.5 oder höher verwenden, können Sie die neue Funktion subprocess.run
verwenden. Diese Funktion ähnelt der obigen Beschreibung, ist jedoch noch flexibler und gibt ein CompletedProcess
- Objekt zurück, wenn der Befehl ausgeführt wird.
Das os-Modul verfügt auch über alle Fork-, Exec- und Spawn-Funktionen, die Sie in einem C-Programm hätten, aber ich empfehle nicht, sie direkt zu verwenden.
Das subprocess
-Modul sollte wahrscheinlich das sein, was Sie verwenden.
Beachten Sie bitte schließlich, dass Sie für alle Methoden, bei denen Sie den endgültigen Befehl übergeben, der von der Shell als String ausgeführt werden soll, die Verantwortung dafür übernehmen müssen. Es gibt schwerwiegende Auswirkungen auf die Sicherheit, wenn einem Teil der Zeichenfolge, den Sie übergeben, nicht vollständig vertraut werden kann. Zum Beispiel, wenn ein Benutzer einen oder 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, beachten Sie diesen Code:
print subprocess.Popen("echo %s " % user_input, stdout=PIPE).stdout.read()
und stellen Sie sich vor, der Benutzer gibt "Meine Mutter hat mich nicht geliebt" & rm -rf/ein.
Ich verwende normalerweise:
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()
Mit den stdout
-Daten in der Pipe können Sie das tun, was Sie möchten. Sie können diese Parameter (stdout=
und stderr=
) einfach weglassen und verhalten sich wie os.system()
.
Einige Hinweise zum Trennen des untergeordneten Prozesses vom aufrufenden (Starten des untergeordneten Prozesses im Hintergrund).
Angenommen, Sie möchten eine lange Aufgabe von einem CGI-Skript aus starten, das heißt, der untergeordnete Prozess sollte länger als der CGI-Skript-Ausführungsprozess sein.
Das klassische Beispiel aus dem Subprozess-Modul docs 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 'call subprocess' warten möchten, bis longtask.py fertig ist. Es ist jedoch nicht klar, was nach der Zeile "etwas mehr Code hier" aus dem Beispiel geschieht.
Meine Zielplattform war Freebsd, aber die Entwicklung fand unter Windows statt, so dass ich das Problem zuerst unter Windows hatte.
Unter Windows (win xp) wird der übergeordnete Prozess erst beendet, wenn longtask.py seine Arbeit beendet hat. Es ist nicht das, was Sie im CGI-Skript wollen. Das Problem ist nicht spezifisch für Python, in der Community PHP sind die Probleme gleich.
Die Lösung besteht darin, DETACHED_PROCESS Process Creation Flag an die zugrunde liegende CreateProcess-Funktion in der Win-API zu übergeben. Falls Sie pywin32 installiert haben, können Sie das Flag aus dem Modul win32process importieren.
DETACHED_PROCESS = 0x00000008
pid = subprocess.Popen([sys.executable, "longtask.py"],
creationflags=DETACHED_PROCESS).pid
/ * UPD 2015.10.27 @eryksun merkt in einem Kommentar an, dass das semantisch korrekte Flag CREATE_NEW_CONSOLE (0x00000010) ist * /
Bei freebsd gibt es ein weiteres Problem: Wenn der übergeordnete Prozess abgeschlossen ist, werden auch die untergeordneten Prozesse abgeschlossen. Und das wollen Sie auch nicht im CGI-Skript. Einige Experimente zeigten, dass das Problem darin bestand, sys.stdout zu teilen. Und die Arbeitslösung war 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 bei freebsd nicht. Wenn jemand weiß, teilen Sie bitte Ihre Ideen. Beim Googeln beim Starten von Hintergrundprozessen in Python gibt es noch keine Erkenntnisse.
import os
cmd = 'ls -al'
os.system(cmd)
Wenn Sie die Ergebnisse des Befehls zurückgeben möchten, können Sie os.popen
verwenden. Dies ist jedoch seit Version 2.6 zugunsten des Moduls subprocess veraltet, auf das andere Antworten bereits eingegangen sind.
Ich würde empfehlen, das Subprozess-Modul anstelle von os.system zu verwenden, da es für Sie die Flucht von Shell übernimmt und daher wesentlich sicherer ist: http://docs.python.org/library/subprocess.html
subprocess.call(['ping', 'localhost'])
import os
os.system("your command")
Beachten Sie, dass dies gefährlich ist, da der Befehl nicht bereinigt wird. Ich überlasse es Ihnen, die relevante Dokumentation zu den Modulen 'os' und 'sys' zu suchen. Es gibt eine Reihe von Funktionen (exec * und spawn *), die ähnliche Aktionen ausführen.
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, ist ls -l
(alle Dateien auflisten). Wenn Sie mehr über eine der Bibliotheken erfahren möchten, habe ich die Dokumentation für jede einzelne aufgelistet und verlinkt.
Quellen:
Dies sind alle Bibliotheken:
Hoffentlich hilft Ihnen das bei der Entscheidung, welche Bibliothek verwendet werden soll :)
subprozess
Mit dem Unterprozess können Sie externe Befehle aufrufen und sie mit ihren Eingabe-/Ausgabe-/Fehler-Pipes (stdin, stdout und stderr) verbinden. Unterprozess ist die Standardeinstellung für die Ausführung 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 os.popen
aufzurufen (Hinweis: Es gibt auch einen Unterprozess.popen). os führt immer die Shell aus und ist eine einfache Alternative für Benutzer, die subprocess.run
nicht benötigen oder nicht wissen.
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ähnliche" Python-Programme. Sie können Programme wie Funktionen wie in sh
aufrufen. 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, sie steuern und Muster in ihrer Ausgabe finden. Dies ist eine bessere Alternative zum Unterprozess für Befehle, die unter Unix ein tty erwarten.
pexpect.run("ls -l") # Run command as normal
child = pexpect.spawn('scp foo [email protected]:.') # 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. Sie können 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
Gesandter
gesandter ist als "Subprozess für Menschen" bekannt. Es wird als praktischer Wrapper für 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 subprocess
eine bessere Alternative ist.
Die Bearbeitung basierte auf dem Kommentar von J. F. 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-Subprozess-Schnittstelle) .
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 von externen Programmen/Befehlen, sogar von ssh, ftp, telnet usw. Sie können nur Folgendes eingeben:
child = pexpect.spawn('ftp 192.168.0.24')
child.expect('(?i)name .*: ')
child.sendline('anonymous')
child.expect('(?i)password')
Wenn Sie die Ausgabe des Befehls benötigen, den Sie aufrufen, , Können Sie subprocess.check_output (Python 2.7+) verwenden.
>>> 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 Parameter Shell .
Wenn Shell
True
ist, wird der angegebene Befehl über die Shell ausgeführt. Dies kann nützlich sein, wenn Sie Python hauptsächlich für den verbesserten Steuerungsfluss verwenden, den es über die meisten System-Shells bietet, und dennoch bequemen Zugriff auf andere Shell-Funktionen wie Shell-Pipes, Dateinamens-Platzhalter, Erweiterung der Umgebungsvariablen und Erweiterung von ~ zu Hause eines Benutzers wünschen Verzeichnis. Beachten Sie jedoch, dass Python selbst Implementierungen vieler Shell-ähnlicher Funktionen bietet (insbesondereglob
,fnmatch
,os.walk()
,os.path.expandvars()
,os.path.expanduser()
undshutil
).
Das Use Unterprozessmodul (Python 3):
import subprocess
subprocess.run(['ls', '-l'])
Dies ist der empfohlene Standardweg. Kompliziertere Aufgaben (Pipes, Ausgabe, Eingabe usw.) können jedoch beim Konstruieren und Schreiben mühsam 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 run
, call
und andere subprocess
-Funktionen zu parsen, falls Sie diese nicht in Listenform bereitstellen möchten (oder können!).
import shlex
import subprocess
subprocess.run(shlex.split('ls -l'))
Wenn Sie sich nicht um externe Abhängigkeiten kümmern, verwenden Sie plumbum :
from plumbum.cmd import ifconfig
print(ifconfig['wlan0']())
Es ist der beste subprocess
-Wrapper. Es ist plattformübergreifend, das heißt, es funktioniert sowohl auf Windows- als auch auf Unix-ähnlichen Systemen. Installieren Sie mit pip install plumbum
.
Eine weitere beliebte Bibliothek ist sh :
from sh import ifconfig
print(ifconfig('wlan0'))
sh
hat jedoch die Windows-Unterstützung eingestellt, so dass es nicht mehr so toll ist wie früher. Installieren Sie mit pip install sh
.
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. (Piping ist allerdings nicht so einfach. Siehe diese Frage für wie .)
Hier sind einige Beispiele aus den Dokumenten .
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
Capture-Ausgabe:
>>> 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 es mit Gesandter . Es ist ein Wrapper für den Subprozess, der wiederum soll ersetzen die älteren Module und Funktionen. Envoy ist ein Unterprozess für Menschen.
Beispielverwendung von die 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 Sachen auch herum:
>>> r = envoy.run('uptime | pbcopy')
>>> r.command
'pbcopy'
>>> r.status_code
0
>>> r.history
[<Response 'uptime'>]
So führe ich meine Befehle aus. Dieser Code enthält alles, was Sie so ziemlich 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()
Ohne Ausgabe des Ergebnisses:
import os
os.system("your command here")
Mit Ausgabe des Ergebnisses:
import commands
commands.getoutput("your command here")
or
commands.getstatusoutput("your command here")
https://docs.python.org/2/library/subprocess.html
... oder für einen ganz einfachen Befehl:
import os
os.system('cat testfile')
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
os.system
ist in Ordnung, aber irgendwie veraltet. Es ist auch nicht sehr sicher. Versuchen Sie stattdessen subprocess
. subprocess
ruft sh nicht direkt auf und ist daher sicherer als os.system
.
Weitere Informationen hier .
Aufruf eines externen Befehls in Python
Verwenden Sie einfach subprocess.run
, das 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 empfiehlt die Dokumentation subprocess.run :
Die empfohlene Methode zum Aufrufen von Unterprozessen ist die Verwendung der Funktion run () für alle Anwendungsfälle, die damit behandelt werden können. Für weitergehende Anwendungsfälle kann die zugrunde liegende Popen-Schnittstelle direkt verwendet werden.
Hier ist ein Beispiel für die einfachste Verwendung - und genau wie gewünscht:
>>> 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 auf den erfolgreichen Abschluss des Befehls und gibt dann ein CompletedProcess
-Objekt zurück. Stattdessen kann es TimeoutExpired
(wenn Sie ihm ein timeout=
-Argument geben) oder CalledProcessError
(wenn es fehlschlägt und Sie check=True
übergeben) erhöhen.
Wie Sie aus dem obigen Beispiel schließen können, werden stdout und stderr standardmäßig an Ihren eigenen stdout und stderr weitergeleitet.
Wir können das zurückgegebene Objekt überprüfen und den gegebenen Befehl sowie 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 stderr
oder stdout
übergeben:
>>> 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 uninteressant, dass die Versionsinformationen statt stdout auf stderr gestellt werden.)
Man könnte leicht von der manuellen Eingabe einer Befehlszeichenfolge (wie in der Frage vorgeschlagen wird) zu einer programmgesteuert erstellten Zeichenfolge übergehen. Erstellen Sie keine Strings 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 von help(run)
gezeigt:
def run(*popenargs, input=None, timeout=None, check=False, **kwargs):
Die popenargs
und kwargs
werden an den Popen
-Konstruktor übergeben. input
kann eine Zeichenfolge von Bytes sein (oder Unicode, wenn Kodierung oder universal_newlines=True
angegeben wird), die an die Standardeingabe des Unterprozesses geleitet wird.
Die Dokumentation beschreibt timeout=
und check=True
besser als ich könnte:
Das Timeout-Argument wird an Popen.communicate () übergeben. Wenn der Timeout abläuft, wird der untergeordnete Prozess beendet und gewartet. Das Die TimeoutExpired-Ausnahme wird erneut ausgelöst, nachdem der untergeordnete Prozess über .__ verfügt. beendet.
Wenn check wahr ist und der Prozess mit einem Exit-Code ungleich Null beendet wird, wird ein Die CalledProcessError-Ausnahme wird ausgelöst. Attribute davon Ausnahme enthalten die Argumente, den Exit-Code und stdout und stderr if Sie wurden gefangen genommen.
und dieses Beispiel für check=True
ist besser als eines, das ich mir vorstellen 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 bedeutet, dass nur die Argumentliste positionell übergeben werden soll. Übergeben Sie also die restlichen Argumente als Schlüsselwortargumente.
Wann stattdessen Popen
verwenden? Ich würde kaum einen Use-Case finden, der allein auf den Argumenten basiert. Durch die direkte Verwendung von Popen
erhalten Sie jedoch Zugriff auf seine Methoden, einschließlich poll
, 'send_signal', 'terminate' und 'wait'.
Hier ist die Popen
Signatur wie in der Quelle angegeben. Ich denke, dass dies die präziseste Verkapselung der Informationen ist (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):
Aber informativer ist 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 os.execvp () - ähnliches Verhalten zum Ausführen des untergeordneten Programms. Unter Windows Die Klasse verwendet die Windows-Funktion CreateProcess (). Die Argumente zu Popen sind wie folgt.
Das Verständnis der verbleibenden Dokumentation zu Popen
wird dem Leser als Übung überlassen.
Es kann so einfach sein:
import os
cmd = "your command"
os.system(cmd)
Benutzen:
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 ist hier die Dokumentation.
subprocess.check_call
ist praktisch, wenn Sie die Rückgabewerte nicht testen möchten. Bei einem Fehler wird eine Ausnahme ausgelöst.
Ich neige dazu, subprocess zusammen mit shlex zu verwenden (um das Ausweichen von Anführungszeichen zu behandeln)
>>> 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)
os.system
erlaubt das Speichern von Ergebnissen nicht. Wenn Sie also Ergebnisse in einer Liste speichern möchten, funktioniert subprocess.call
.
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 einen Teilprozess ausprobiert und die Ausführung war erfolgreich. <B> konnte jedoch nicht mit <a> ..__ kommunizieren. Alles ist normal, wenn ich beide vom Terminal aus laufe.
Noch mehr: (HINWEIS: kwrite verhält sich anders als andere Anwendungen. Wenn Sie Folgendes mit Firefox versuchen, werden die Ergebnisse nicht gleich sein.)
Wenn Sie os.system("kwrite")
versuchen, bleibt der Programmablauf stehen, bis der Benutzer kwrite beendet. Um das zu überwinden, versuchte ich stattdessen os.system(konsole -e kwrite)
. Dieses Mal lief das Programm weiter, aber kwrite wurde zum Unterprozess der Konsole.
Jeder, der kwrite ausführt, ist kein Unterprozess (d. H. Er muss im Systemmonitor am linken Rand des Baums erscheinen).
Ich mag Shell_Command wegen seiner Einfachheit. Es ist auf dem Subprozess-Modul aufgebaut.
Hier ist ein Beispiel aus den Dokumenten:
>>> 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
verwenden Sie das OS-Modul
import os
os.system("your command")
z.B
import os
os.system("ifconfig")
Schamloser Plug, ich habe dafür eine Bibliothek geschrieben: P https://github.com/houqp/Shell.py
Es ist im Grunde ein Wrapper für Popen und Shlex für jetzt. Es unterstützt auch Piping-Befehle, damit Sie Befehle in Python einfacher verketten können. So kannst du Dinge tun wie:
ex('echo hello Shell.py') | "awk '{print $2}'"
Für den Fall, dass Sie einen externen Befehl aufrufen möchten, der unabhängig ausgeführt wird (wird ausgeführt, nachdem das Python-Skript beendet wurde), können Sie eine einfache Warteschlange als task spooler oder den Befehl at 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 ausgeführten Prozesse ("Slots") wie folgt festlegen:
ts -S <number-of-slots>
Die Installation von ts
erfordert keine Administratorrechte. Sie können es mit einer einfachen make
aus dem Quellcode herunterladen und kompilieren, es Ihrem Pfad hinzufügen und fertig.
Sie können Popen verwenden und dann den Status der Prozedur überprüfen:
from subprocess import Popen
proc = Popen(['ls', '-l'])
if proc.poll() is None:
proc.kill()
Check out subprozess.Popen .
In Windows können Sie einfach das Modul subprocess
importieren und externe Befehle ausführen, indem Sie subprocess.Popen()
, subprocess.Popen().communicate()
und subprocess.Popen().wait()
wie folgt aufrufen:
# 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
Sehr einfachste Möglichkeit, einen Befehl auszuführen und das Ergebnis zurückzuholen:
from commands import getstatusoutput
try:
return getstatusoutput("ls -ltr")
except Exception, e:
return None
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 von nova net-list
+--------------------------------------+------------+------+
| 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
Hier sind meine zwei Cents: Dies ist aus meiner Sicht die beste Vorgehensweise, wenn Sie mit externen Befehlen umgehen ...
Dies sind die Rückgabewerte der Execute-Methode ...
pass, stdout, stderr = execute(["ls","-la"],"/home/user/desktop")
Dies ist die Ausführungsmethode ...
def execute(cmdArray,workingDir):
stdout = ''
stderr = ''
try:
try:
process = subprocess.Popen(cmdArray,cwd=workingDir, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=1)
except OSError:
return [False, '', 'ERROR : command(' + ' '.join(cmdArray) + ') could not get executed!']
for line in iter(process.stdout.readline, b''):
try:
echoLine = line.decode("utf-8")
except:
echoLine = str(line)
stdout += echoLine
for line in iter(process.stderr.readline, b''):
try:
echoLine = line.decode("utf-8")
except:
echoLine = str(line)
stderr += echoLine
except (KeyboardInterrupt,SystemExit) as err:
return [False,'',str(err)]
process.stdout.close()
returnCode = process.wait()
if returnCode != 0 or stderr != '':
return [False, stdout, stderr]
else:
return [True, stdout, stderr]
Invoke ist ein Python (2.7 und 3.4+) Taskausführungswerkzeug und eine Bibliothek. Es bietet eine saubere High-Level-API zum Ausführen von Shell-Befehlen
>>> from invoke import run
>>> cmd = "pip install -r requirements.txt"
>>> result = run(cmd, hide=True, warn=True)
>>> print(result.ok)
True
>>> print(result.stdout.splitlines()[-1])
Successfully installed invocations-0.13.0 pep8-1.5.7 spec-1.3.1
Hier wird ein externer Befehl aufgerufen und die Ausgabe des Befehls zurückgegeben oder gedruckt:
Python Subprozess check_output ist gut für
Führen Sie den Befehl mit Argumenten aus und geben Sie die Ausgabe als Byte-Zeichenfolge zurück.
import subprocess
proc = subprocess.check_output('ipconfig /all')
print proc
Benutzen:
import subprocess
p = subprocess.Popen("df -h", Shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
print p.split("\n")
Es gibt Nice-Ausgabe, mit der einfacher zu arbeiten ist:
['Filesystem Size Used Avail Use% Mounted on',
'/dev/sda6 32G 21G 11G 67% /',
'none 4.0K 0 4.0K 0% /sys/fs/cgroup',
'udev 1.9G 4.0K 1.9G 1% /dev',
'tmpfs 387M 1.4M 386M 1% /run',
'none 5.0M 0 5.0M 0% /run/lock',
'none 1.9G 58M 1.9G 3% /run/shm',
'none 100M 32K 100M 1% /run/user',
'/dev/sda5 340G 222G 100G 69% /home',
'']
Um die Diskussion noch zu erweitern, können Sie bei Verwendung einer Python-Konsole externe Befehle von IPython aufrufen. In der IPython-Eingabeaufforderung können Sie Shell-Befehle mit dem Präfix '!' Aufrufen. Sie können auch Python-Code mit der Shell kombinieren und die Ausgabe von Shell-Skripts Python-Variablen zuweisen.
Zum Beispiel:
In [9]: mylist = !ls
In [10]: mylist
Out[10]:
['file1',
'file2',
'file3',]
Aufruf eines externen Befehls in Python
Eine einfache Möglichkeit, einen externen Befehl aufzurufen, ist os.system(...)
. Und diese Funktion gibt den Exit-Wert des Befehls zurück. Der Nachteil ist jedoch, dass wir nicht stdout und stderr bekommen.
ret = os.system('some_cmd.sh')
if ret != 0 :
print 'some_cmd.sh execution returned failure'
Aufruf eines externen Befehls in Python im Hintergrund
subprocess.Popen
bietet mehr Flexibilität für die Ausführung eines externen Befehls als die Verwendung von os.system
. Wir können einen Befehl im Hintergrund starten und warten, bis er beendet ist. Und danach können wir stdout und stderr bekommen.
proc = subprocess.Popen(["./some_cmd.sh"], stdout=subprocess.PIPE)
print 'waiting for ' + str(proc.pid)
proc.wait()
print 'some_cmd.sh execution finished'
(out, err) = proc.communicate()
print 'some_cmd.sh output : ' + out
Aufruf eines lang laufenden externen Befehls in Python im Hintergrund und nach einiger Zeit zum Stoppen
Wir können sogar einen lang laufenden Prozess mit subprocess.Popen
im Hintergrund starten und ihn irgendwann beenden, sobald seine Aufgabe erledigt ist.
proc = subprocess.Popen(["./some_long_run_cmd.sh"], stdout=subprocess.PIPE)
# Do something else
# Now some_long_run_cmd.sh exeuction is no longer needed, so kill it
os.system('kill -15 ' + str(proc.pid))
print 'Output : ' proc.communicate()[0]
Es gibt viele verschiedene Möglichkeiten, externe Befehle in Python auszuführen. Alle haben ihre eigenen Vorzüge und Nachteile.
Meine Kollegen und ich haben Python-Systemverwaltungstools geschrieben. Daher müssen Sie viele externe Befehle ausführen. Manchmal möchten Sie, dass sie blockiert oder asynchron ausgeführt werden, ein Timeout ausführen, jede Sekunde aktualisieren usw.
Es gibt auch verschiedene Möglichkeiten, den Rückgabecode und die Fehler zu behandeln, Sie können die Ausgabe analysieren und neue Eingaben bereitstellen (in einer Art expect ). Oder Sie müssen stdin, stdout und stderr umleiten, um in einem anderen tty zu laufen (z. B. bei Verwendung des Bildschirms).
Sie müssen also wahrscheinlich viele Wrapper um den externen Befehl schreiben. Hier ist also ein Python-Modul, das wir geschrieben haben, das fast alles, was Sie möchten, handhaben kann. Wenn nicht, ist es sehr flexibel, sodass Sie es leicht erweitern können:
https://github.com/hpcugent/vsc-base/blob/master/lib/vsc/utils/run.py
Als Beispiel (in Linux):
import subprocess
subprocess.run('mkdir test.dir', Shell=True)
Dadurch wird test.dir im aktuellen Verzeichnis .. erstellt. Beachten Sie, dass dies auch funktioniert:
import subprocess
subprocess.call('mkdir test.dir', Shell=True)
Der entsprechende Code für os.system lautet:
import os
os.system('mkdir test.dir')
Die beste Vorgehensweise wäre die Verwendung eines Unterprozesses anstelle von os, wobei .run gegenüber .call bevorzugt wird. Alles, was Sie über den Teilprozess wissen müssen, ist hier . Beachten Sie außerdem, dass die gesamte Python-Dokumentation unter hier zum Download verfügbar ist. Ich habe das PDF als .Zip-Paket heruntergeladen. Ich erwähne das, weil es eine schöne Übersicht über das os-Modul in tutorial.pdf gibt (Seite 81). Außerdem ist es eine maßgebliche Ressource für Python-Codierer.
Für Python 3.5 und höher wird empfohlen, dass Sie die Funktion run aus dem Subprozess-Modul verwenden. Dadurch wird ein CompletedProcess
-Objekt zurückgegeben, aus dem Sie die Ausgabe sowie den Rückgabecode abrufen können.
from subprocess import PIPE, run
command = ['echo', 'hello']
result = run(command, stdout=PIPE, stderr=PIPE, universal_newlines=True)
print(result.returncode, result.stdout, result.stderr)
Ich verwende häufig die folgende Funktion für externe Befehle, und dies ist besonders praktisch für lange laufende Prozesse . Die folgende Methode tails verarbeitet die Ausgabe , während ausgeführt wird, und gibt die Ausgabe zurück. löst eine Ausnahme aus , wenn der Prozess fehlschlägt.
Es wird ausgegeben, wenn der Prozess mit der Methode poll () für den Prozess ausgeführt wird.
import subprocess,sys
def exec_long_running_proc(command, args):
cmd = "{} {}".format(command, " ".join(str(arg) if ' ' not in arg else arg.replace(' ','\ ') for arg in args))
print(cmd)
process = subprocess.Popen(cmd, Shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
# Poll process for new output until finished
while True:
nextline = process.stdout.readline().decode('UTF-8')
if nextline == '' and process.poll() is not None:
break
sys.stdout.write(nextline)
sys.stdout.flush()
output = process.communicate()[0]
exitCode = process.returncode
if (exitCode == 0):
return output
else:
raise Exception(command, exitCode, output)
Sie können es so aufrufen:
exec_long_running_proc(command = "Hive", args=["-f", hql_path])
Ein einfacher Weg ist die Verwendung des os-Moduls:
import os
os.system('ls')
Alternativ können Sie auch das Subprozess-Modul verwenden
import subprocess
subprocess.check_call('ls')
Wenn Sie möchten, dass das Ergebnis in einer Variablen gespeichert wird, versuchen Sie Folgendes:
import subprocess
r = subprocess.check_output('ls')
Verwenden Sie subprocess.call :
from subprocess import call
# using list
call(["echo", "Hello", "world"])
# single string argument varies across platforms so better split it
call("echo Hello world".split(" "))
Die Verwendung der Funktion Popen
des Moduls subprocess
Python ist die einfachste Möglichkeit, Linux-Befehle auszuführen. In diesem Fall gibt die Funktion Popen.communicate()
Ihre Befehle aus. Zum Beispiel
import subprocess
..
process = subprocess.Popen(..) # Pass command and arguments to the function
stdout, stderr = process.communicate() # Get command output and error
..
Es gibt viele Möglichkeiten, einen Befehl aufzurufen.
wenn and.exe
zwei Parameter benötigt. In cmd können wir sample.exe
Aufrufen und dies verwenden: and.exe 2 3
Und es wird 5
Auf dem Bildschirm angezeigt.
Wenn wir ein Python Skript verwenden, um and.exe
Aufzurufen, sollten wir wie folgt vorgehen ..
os.system(cmd,...)
os.system(("and.exe" + " " + "2" + " " + "3"))
os.popen(cmd,...)
os.popen(("and.exe" + " " + "2" + " " + "3"))
subprocess.Popen(cmd,...)
subprocess.Popen(("and.exe" + " " + "2" + " " + "3"))
Es ist zu schwer, also können wir cmd mit einem Leerzeichen verbinden:
import os
cmd = " ".join(exename,parameters)
os.popen(cmd)
Wenn Sie einen Shell-Befehl von einem Python-Notebook aus aufrufen müssen (wie Jupyter , Zeppelin, Databricks oder Google Cloud Datalab), können Sie einfach das Präfix !
verwenden.
Zum Beispiel,
!ls -ilF
Ich habe eine kleine Bibliothek geschrieben, um bei diesem Anwendungsfall zu helfen:
https://pypi.org/project/citizenshell/
Es kann mit installiert werden
pip install citizenshell
Und dann wie folgt verwendet:
from citizenshell import sh
assert sh("echo Hello World") == "Hello World"
Sie können stdout von stderr trennen und den Exit-Code wie folgt extrahieren:
result = sh(">&2 echo error && echo output && exit 13")
assert result.stdout() == ["output"]
assert result.stderr() == ["error"]
assert result.exit_code() == 13
Und das Coole ist, dass Sie nicht warten müssen, bis die zugrunde liegende Shell beendet ist, bevor Sie mit der Verarbeitung der Ausgabe beginnen:
for line in sh("for i in 1 2 3 4; do echo -n 'It is '; date +%H:%M:%S; sleep 1; done", wait=False)
print ">>>", line + "!"
druckt die Zeilen so, wie sie verfügbar sind, dank dem wait = False
>>> It is 14:24:52!
>>> It is 14:24:53!
>>> It is 14:24:54!
>>> It is 14:24:55!
Weitere Beispiele finden Sie unter https://github.com/meuter/citizenshell
Es gibt zwei wichtige Möglichkeiten, Shell-Befehle mit Python auszuführen. Die beiden unten genannten Beispiele zeigen, wie man mit Python den Namen des aktuellen Arbeitsverzeichnisses (pwd
) erhält. Sie können anstelle von pwd
jeden anderen Unix-Befehl verwenden.
1.> 1. Methode: Man kann das Modul os aus Python und die Funktion system () verwenden, um Shell-Befehle in Python auszuführen.
import os
os.system('pwd')
Ausgabe:
/Users/siddharth
1.> 2. Methode: Eine andere Möglichkeit ist die Verwendung des Moduls Subprozess und der Funktion call () .
import subprocess
subprocess.call('pwd')
Ausgabe:
/Users/siddharth
Ich würde die folgende Methode "run" empfehlen, die uns dabei helfen wird, STDOUT, STDERR und den Exit-Status als Wörterbuch zu erhalten. Der Aufrufer kann das Wörterbuch mit der 'run'-Methode zurückschicken, um den tatsächlichen Status des Prozesses zu erfahren.
def run (cmd):
print "+ DEBUG exec({0})".format(cmd)
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, Shell=True)
(out, err) = p.communicate()
ret = p.wait()
out = filter(None, out.split('\n'))
err = filter(None, err.split('\n'))
ret = True if ret == 0 else False
return dict({'output': out, 'error': err, 'status': ret})
#end
Nach einiger Recherche habe ich den folgenden Code, der für mich sehr gut funktioniert. Grundsätzlich werden sowohl stdout als auch stderr in Echtzeit gedruckt. Hoffe, es hilft jemand anderem, der es braucht.
stdout_result = 1
stderr_result = 1
def stdout_thread(pipe):
global stdout_result
while True:
out = pipe.stdout.read(1)
stdout_result = pipe.poll()
if out == '' and stdout_result is not None:
break
if out != '':
sys.stdout.write(out)
sys.stdout.flush()
def stderr_thread(pipe):
global stderr_result
while True:
err = pipe.stderr.read(1)
stderr_result = pipe.poll()
if err == '' and stderr_result is not None:
break
if err != '':
sys.stdout.write(err)
sys.stdout.flush()
def exec_command(command, cwd=None):
if cwd is not None:
print '[' + ' '.join(command) + '] in ' + cwd
else:
print '[' + ' '.join(command) + ']'
p = subprocess.Popen(
command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd
)
out_thread = threading.Thread(name='stdout_thread', target=stdout_thread, args=(p,))
err_thread = threading.Thread(name='stderr_thread', target=stderr_thread, args=(p,))
err_thread.start()
out_thread.start()
out_thread.join()
err_thread.join()
return stdout_result + stderr_result
Sultan ist ein neues Paket für diesen Zweck. Bietet einige Details zum Verwalten von Benutzerrechten und zum Hinzufügen hilfreicher Fehlermeldungen.
from sultan.api import Sultan
with Sultan.load(Sudo=True, hostname="myserver.com") as sultan:
sultan.yum("install -y tree").run()
Ich habe einen Wrapper geschrieben, um Fehler zu behandeln und die Ausgabe und anderes Material umzuleiten.
import shlex
import psutil
import subprocess
def call_cmd(cmd, stdout=sys.stdout, quiet=False, Shell=False, raise_exceptions=True, use_shlex=True, timeout=None):
"""Exec command by command line like 'ln -ls "/var/log"'
"""
if not quiet:
print("Run %s", str(cmd))
if use_shlex and isinstance(cmd, (str, unicode)):
cmd = shlex.split(cmd)
if timeout is None:
process = subprocess.Popen(cmd, stdout=stdout, stderr=sys.stderr, Shell=shell)
retcode = process.wait()
else:
process = subprocess.Popen(cmd, stdout=stdout, stderr=sys.stderr, Shell=shell)
p = psutil.Process(process.pid)
finish, alive = psutil.wait_procs([p], timeout)
if len(alive) > 0:
ps = p.children()
ps.insert(0, p)
print('waiting for timeout again due to child process check')
finish, alive = psutil.wait_procs(ps, 0)
if len(alive) > 0:
print('process {} will be killed'.format([p.pid for p in alive]))
for p in alive:
p.kill()
if raise_exceptions:
print('External program timeout at {} {}'.format(timeout, cmd))
raise CalledProcessTimeout(1, cmd)
retcode = process.wait()
if retcode and raise_exceptions:
print("External program failed %s", str(cmd))
raise subprocess.CalledProcessError(retcode, cmd)
Man kann es so nennen:
cmd = 'ln -ls "/var/log"'
stdout = 'out.txt'
call_cmd(cmd, stdout)
Das Subprozess-Modul , das oben von Eli beschrieben wurde, ist sehr mächtig, aber die Syntax für den Aufruf eines Sumpf-Standardsystems und das Überprüfen seiner Ausgabe ist unnötig prolix.
Der einfachste Weg, einen Systemaufruf durchzuführen, ist mit dem Befehlsmodul (nur Linux).
> import commands
> commands.getstatusoutput("grep matter alice-in-wonderland.txt")
(0, "'Then it doesn't matter which way you go,' said the Cat.")
Das erste Element im Tupel ist der Rückkehrcode des Prozesses. Das zweite Element ist seine Standardausgabe (und Standardfehler, zusammengeführt).
Die Python-Entwickler haben das Befehlsmodul "abgelehnt", aber das bedeutet nicht, dass Sie es nicht verwenden sollten. Nur, dass sie es nicht mehr entwickeln, was in Ordnung ist, weil es bereits perfekt ist (bei seiner kleinen, aber wichtigen Funktion).
Da einige Antworten auf frühere Versionen von Python bezogen waren oder os.system
-Modul verwendeten, poste ich diese Antwort für Leute wie mich, die subprocess
in python 3.5+
verwenden möchten. Das Folgende hat mir den Trick unter Linux gebracht:
import subprocess
#subprocess.run() returns a completed process object that can be inspected
c = subprocess.run(["ls", "-ltrh"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
print(c.stdout.decode('utf-8'))
Wie in der documentation erwähnt, sind PIPE
Werte Byte-Sequenzen, und für eine korrekte Darstellung sollte die Decodierung berücksichtigt werden. Für spätere Versionen von Python werden text=True
und encoding='utf-8'
zu den Warnungen von subprocess.run()
hinzugefügt.
Die Ausgabe des oben genannten Codes ist:
total 113M
-rwxr-xr-x 1 farzad farzad 307 Jan 15 2018 vpnscript
-rwxrwxr-x 1 farzad farzad 204 Jan 15 2018 ex
drwxrwxr-x 4 farzad farzad 4.0K Jan 22 2018 scripts
.... # some other lines
Sie können auch subprocess.getoutput()
und subprocess.getstatusutput()
verwenden, bei denen es sich um Legacy Shell Invocation Functions aus dem veralteten commands
-Modul handelt, d. H :
subprocess.getstatusoutput(cmd)
Rückgabe (
exitcode
,output
) der Ausführung voncmd
in einer Shell.
subprocess.getoutput(cmd)
Gibt die Ausgabe (
stdout
undstderr
) der Ausführung voncmd
in einer Shell zurück.
Sie können import
und dann den Dateinamen verwenden. Zum Beispiel mit dem eingebauten Modul 'random': import random
Wenn Sie in den BefehlenNICHTBenutzereingaben verwenden, können Sie diese verwenden
from os import getcwd
from subprocess import check_output
from shlex import quote
def sh(command):
return check_output(quote(command), Shell=True, cwd=getcwd(), universal_newlines=True).strip()
Und benutze es als
branch = sh('git rev-parse --abbrev-ref HEAD')
Shell=True
wird eine Shell erzeugen, so dass Sie Pipe und solche Shell-Dinge verwenden können sh('ps aux | grep python')
. Dies ist sehr praktisch, um fest codierte Befehle auszuführen und die Ausgabe zu verarbeiten. Der universal_lines=True
stellt sicher, dass die Ausgabe in einer Zeichenfolge statt binär zurückgegeben wird.
cwd=getcwd()
stellt sicher, dass der Befehl mit demselben Arbeitsverzeichnis wie der Interpreter ausgeführt wird. Dies ist praktisch, damit git-Befehle wie im obigen Beispiel für den Namen des git-Zweigs funktionieren.
Einige Rezepte
sh('free -m').split('\n')[1].split()[1]
sh('df -m /').split('\n')[1].split()[4][0:-1]
sum(map(float, sh('ps -ef -o pcpu').split('\n')[1:])
Dies ist jedoch nicht sicher für Benutzereingaben, aus den Dokumenten:
Sicherheitsüberlegungen¶
Im Gegensatz zu einigen anderen popen-Funktionen wird diese Implementierung niemals implizit eine System-Shell aufrufen. Dies bedeutet, dass alle Zeichen, einschließlich Shell-Metazeichen, sicher an untergeordnete Prozesse übergeben werden können. Wenn die Shell explizit über Shell = True aufgerufen wird, muss die Anwendung sicherstellen, dass alle Leerzeichen und Metazeichen in Anführungszeichen gesetzt werden, um Sicherheitsanfälligkeiten bei der Shell-Injektion zu vermeiden.
Bei Verwendung von Shell = True kann die Funktion shlex.quote () verwendet werden, um Whitespace- und Shell-Metazeichen in Zeichenfolgen, die zum Erstellen von Shell-Befehlen verwendet werden sollen, ordnungsgemäß zu umgehen.
Sogar die Verwendung der Funktion shlex.quote()
ist gut, um ein wenig paranoid zu bleiben, wenn Benutzereingaben für Shell-Befehle verwendet werden. Eine Möglichkeit besteht darin, einen Hardcode-Befehl zu verwenden, um eine allgemeine Ausgabe vorzunehmen und nach Benutzereingaben zu filtern. Auf jeden Fall wird mit Shell=False
sichergestellt, dass nur der Prozess ausgeführt wird, den Sie ausführen möchten, oder es wird ein No such file or directory
-Fehler angezeigt.
Außerdem hat dies einen gewissen Einfluss auf die Leistung von Shell=True
. Aus meinen Tests geht hervor, dass es ungefähr 20% langsamer ist als Shell=False
(Standardeinstellung).
In [50]: timeit("check_output('ls -l'.split(), universal_newlines=True)", number=1000, globals=globals())
Out[50]: 2.6801227919995654
In [51]: timeit("check_output('ls -l', universal_newlines=True, Shell=True)", number=1000, globals=globals())
Out[51]: 3.243950183999914
Wenn Sie ein Python -Shell-Skript schreiben und IPython auf Ihrem System installiert haben, können Sie mit der Knall-Magie einen Befehl in IPython ausführen:
!ls
filelist = !ls