6121 Stimmen

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

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

0 Stimmen

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

84voto

athanassis Punkte 1007

Prüfen Sie auch die Python-Bibliothek "pexpect".

Es ermöglicht die interaktive Steuerung von externen Programmen/Befehlen, sogar ssh, ftp, telnet, etc. Sie können einfach etwas eingeben wie:

child = pexpect.spawn('ftp 192.168.0.24')

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

child.sendline('anonymous')

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

83voto

Facundo Casco Punkte 9389

Wenn Sie die Ausgabe des aufgerufenen Befehls benötigen, dann können Sie 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 die Shell Parameter.

Wenn das Gehäuse True wird der angegebene Befehl über die Shell ausgeführt. Dies kann nützlich sein, wenn Sie Python in erster Linie wegen des verbesserten Kontrollflusses verwenden, den es im Vergleich zu den meisten System-Shells bietet, und dennoch bequemen Zugriff auf andere Shell-Funktionen wie Shell-Pipes, Dateinamen-Wildcards, Umgebungsvariablen-Expansion und die Expansion von ~ zum Home-Verzeichnis eines Benutzers wünschen. Beachten Sie jedoch, dass Python selbst Implementierungen vieler Shell-ähnlicher Funktionen bietet (insbesondere, glob , fnmatch , os.walk() , os.path.expandvars() , os.path.expanduser() et shutil ).

2 Stimmen

Beachten Sie, dass check_output erfordert eine Liste anstelle einer Zeichenkette. Wenn Sie sich nicht auf Leerzeichen in Anführungszeichen verlassen, um Ihren Aufruf gültig zu machen, ist der einfachste und lesbarste Weg, dies zu tun subprocess.check_output("ls -l /dev/null".split()) .

0 Stimmen

Wie in der Antwort vage angedeutet und in vielen anderen Antworten auf dieser Seite ausführlicher erläutert, können Sie eine Liste übergeben, oder mit shell=True eine einzelne Zeichenkette, die dann von der Shell geparst und ausgeführt wird. Die Verwendung von einfachen .split() ist unter den von Ihnen genannten Umständen in Ordnung, aber Anfänger verstehen in der Regel die Feinheiten nicht; Sie sind wahrscheinlich besser beraten, wenn Sie shlex.split() die Anführungszeichen und Backslash-Escapes korrekt behandelt.

70voto

Joe Punkte 15528

Aktualisierung:

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, wie .)

Hier sind einige Beispiele aus die Dokumentation .

Einen Prozess ausführen:

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

Anheben bei fehlgeschlagenem Lauf:

>>> 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 einfangen:

>>> 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 zu versuchen Abgesandter . Es ist ein Wrapper für subprocess, der seinerseits zielt darauf ab, zu ersetzen die älteren Module und Funktionen. Envoy ist ein Unterprozess für Menschen.

Anwendungsbeispiel aus 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
''

Auch Rohrleitungsmaterial:

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

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

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

66voto

Usman Khan Punkte 681

So führe ich meine Befehle aus. Dieser Code hat so ziemlich alles, was man braucht

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

4 Stimmen

Ich denke, dass dies für fest kodierte Befehle akzeptabel ist, wenn es die Lesbarkeit erhöht.

0 Stimmen

Eine Erklärung wäre angebracht. Z. B.: Was ist die Idee/der Sinn?

57voto

Ausführen eines Programms oder Aufrufen eines Systembefehls in Python

Einfach, verwenden subprocess.run die eine CompletedProcess Objekt:

>>> from subprocess import run
>>> from shlex import split
>>> completed_process = run(split('python --version'))
Python 3.8.8
>>> completed_process
CompletedProcess(args=['python', '--version'], returncode=0)

( run will eine Liste von lexikalisch geparsten Shell-Argumenten - das ist das, was Sie in eine Shell eingeben würden, getrennt durch Leerzeichen, aber nicht dort, wo die Leerzeichen in Anführungszeichen stehen, also verwenden Sie eine spezielle Funktion, split um das aufzuteilen, was Sie buchstäblich in Ihre Shell eingeben würden)

Warum?

Ab Python 3.5 empfiehlt die Dokumentation subprocess.run :

Der empfohlene Ansatz für den Aufruf von Unterprozessen ist die Verwendung der Funktion run() für alle Anwendungsfälle, die sie verarbeiten kann. Für fortgeschrittenere Anwendungsfälle kann die zugrunde liegende Popen-Schnittstelle direkt verwendet werden.

Hier ist ein Beispiel für die einfachste mögliche Verwendung - und sie tut genau das, was verlangt wird:

>>> from subprocess import run
>>> from shlex import split
>>> completed_process = run(split('python --version'))
Python 3.8.8
>>> completed_process
CompletedProcess(args=['python', '--version'], returncode=0)

run wartet, bis der Befehl erfolgreich beendet wurde, und gibt dann ein CompletedProcess Gegenstand. Stattdessen kann es TimeoutExpired (wenn Sie ihm eine timeout= Argument) oder CalledProcessError (wenn er fehlschlägt und Sie bestehen check=True ).

Wie Sie aus dem obigen Beispiel ersehen 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 gegebenen Befehl und den Rückgabecode sehen:

>>> completed_process.args
['python', '--version']
>>> completed_process.returncode
0

Erfassen der Ausgabe

Wenn Sie die Ausgabe aufzeichnen möchten, können Sie subprocess.PIPE an die entsprechende stderr o stdout :

>>> from subprocess import PIPE
>>> completed_process = run(shlex.split('python --version'), stdout=PIPE, stderr=PIPE)
>>> completed_process.stdout
b'Python 3.8.8\n'
>>> completed_process.stderr
b''

Und diese jeweiligen Attribute geben Bytes zurück.

Übergabe einer Befehlsliste

Man könnte leicht von der manuellen Eingabe eines Befehlsstrings (wie die Frage vorschlägt) zur Bereitstellung eines programmatisch erstellten Strings übergehen. Erstellen Sie Strings nicht programmatisch. Dies ist ein potenzielles Sicherheitsproblem. Es ist besser, davon auszugehen, dass Sie der Eingabe nicht trauen.

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

Hinweis, nur args sollte positionell übergeben werden.

Vollständige Unterschrift

Hier ist die tatsächliche Unterschrift in der Quelle und wie sie von help(run) :

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

Die popenargs y kwargs werden an den Popen Konstrukteur. input kann eine Zeichenkette aus Bytes sein (oder Unicode, wenn die Kodierung oder universal_newlines=True ), die an die stdin des Unterprozesses weitergeleitet wird.

Die Dokumentation beschreibt timeout= y check=True besser als ich es könnte:

Das Argument timeout wird an Popen.communicate() übergeben. Wenn die Zeitüberschreitung abläuft, wird der Kindprozess beendet und es wird auf ihn gewartet. Die TimeoutExpired-Ausnahme wird erneut ausgelöst, nachdem der Kindprozess beendet wurde.

Wenn check true ist und der Prozess mit einem Exit-Code ungleich Null beendet wird, wird ein CalledProcessError-Ausnahme ausgelöst. Die Attribute dieser Ausnahme enthalten die Argumente, den Exit-Code sowie stdout und stderr, falls sie aufgezeichnet wurden.

und dieses Beispiel für check=True ist besser als eine, die ich mir ausdenken 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 sie in der Dokumentation angegeben ist:

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 args-Liste positionell übergeben werden soll. Übergeben Sie also die restlichen Argumente als Schlüsselwortargumente.

Popen

Wenn Sie Popen stattdessen? Ich würde mich schwer tun, allein auf der Grundlage der Argumente einen Anwendungsfall zu finden. Direkte Verwendung von Popen würde Ihnen jedoch Zugang zu seinen Methoden geben, einschließlich poll send_signal", "terminate" und "wait".

Hier ist die Popen Unterschrift wie angegeben in die Quelle . Ich denke, dies ist die präziseste Verkapselung 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=True,
             shell=False, cwd=None, env=None, universal_newlines=None,
             startupinfo=None, creationflags=0,
             restore_signals=True, start_new_session=False,
             pass_fds=(), *, user=None, group=None, extra_groups=None,
             encoding=None, errors=None, text=None, umask=-1, pipesize=-1):

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=None, startupinfo=None, creationflags=0, 
restore_signals=True, start_new_session=False, pass_fds=(), *, group=None, 
extra_groups=None, user=None, umask=-1, encoding=None, errors=None, 
text=None)

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

Verstehen der übrigen Dokumentation über Popen wird als Übung für den Leser belassen.

1 Stimmen

Ein einfaches Beispiel für die wechselseitige Kommunikation zwischen einem Hauptprozess und einem Unterprozess finden Sie hier: stackoverflow.com/a/52841475/1349673

CodeJaeger.com

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

Powered by:

X