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?

5569
freshWoWer 18 Sept. 2008 im 05:35

27 Antworten

Beste Antwort

Schauen Sie sich das Unterprozess -Modul in der Standardbibliothek an:

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

Der Vorteil von subprocess gegenüber system besteht darin, dass es flexibler ist (Sie können den stdout, stderr, den "echten" Statuscode, eine bessere Fehlerbehandlung usw. Erhalten ...).

In der offiziellen Dokumentation wird das Modul subprocess gegenüber der Alternative {empfohlen {X1}}:

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

Die Ersetzen älterer Funktionen durch das Unterprozessmodul < Der Abschnitt / a> 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"])
4552
Corey Goldberg 31 Aug. 2019 im 03:17

Ich verwende in der Regel Unterprozess zusammen mit shlex (um das Entkommen von Zeichenfolgen in 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)
21
Emil Stenström 30 Apr. 2014 im 14:37

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

21
cdunn2001 18 Jän. 2011 im 19:21

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 das Problem zuerst unter Windows hatte.

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 Prozesserstellung zu übergeben Markieren Sie die zugrunde liegende CreateProcess-Funktion in der Windows-API. 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 stellt in einem Kommentar unten 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 Arbeitslö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.

220
Peter Mortensen 29 Nov. 2019 im 21:46

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, Unterprozess .call funktioniert ähnlich.

ProTip: shlex.split kann Ihnen beim Parsen helfen Der Befehl für run, call und andere subprocess Funktionen, falls Sie diese nicht möchten (oder nicht können!), wird in Form von Listen bereitgestellt:

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 der beste subprocess Wrapper. Es ist plattformübergreifend, d. H. Es funktioniert sowohl auf Windows- als auch auf Unix-ähnlichen Systemen. Installation durch pip install plumbum.

Eine weitere beliebte Bibliothek ist sh:

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

sh hat jedoch die Windows-Unterstützung eingestellt, sodass es nicht mehr so toll ist wie früher. Installation durch pip install sh.

67
6 revs, 2 users 79% 29 Nov. 2019 im 21:54

Wenn Sie die Ausgabe des Befehls benötigen, den Sie aufrufen, Dann 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 die 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 erweiterten Steuerungsfluss verwenden, den es für 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 Implementierungen vieler Shell-ähnlicher Funktionen bietet (insbesondere glob, fnmatch, os.walk(), os.path.expandvars(), os.path.expanduser() und { {X6}}).

67
Peter Mortensen 3 Juni 2018 im 20:18

So einfach kann es sein:

import os
cmd = "your command"
os.system(cmd)
27
Samadi Salahedine 8 Juni 2018 im 12:06

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

Warum?

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

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 auf den erfolgreichen Abschluss des Befehls und gibt dann ein CompletedProcess Objekt zurück. Es kann stattdessen TimeoutExpired (wenn Sie ihm ein timeout= Argument geben) oder CalledProcessError (wenn es fehlschlägt und Sie check=True bestehen) auslösen.

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.PIPE an das 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 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 args positionell übergeben werden sollte.

Vollständige Unterschrift

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 dem Konstruktor Popen übergeben. input kann eine Folge von Bytes (oder Unicode, wenn Codierung angegeben ist, oder universal_newlines=True) sein, die an den Standard des Unterprozesses weitergeleitet werden.

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 beendet 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 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

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

Wenn Sie stattdessen Popen 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 Signatur, wie in der Quelle . 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 zu Popen wird dem Leser als Übung überlassen.

34
Aaron Hall 18 Okt. 2017 im 16:37

Ich würde empfehlen, das Subprozess -Modul anstelle von os.system zu verwenden, da es Shell-Escape-Aktionen ausführt für Sie und ist daher viel sicherer.

subprocess.call(['ping', 'localhost'])
139
Nicolas Gervais 24 Feb. 2020 im 01:01

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
16
Peter Mortensen 28 Mai 2017 im 23:08

Verwenden:

import os

cmd = 'ls -al'

os.system(cmd)

Betriebssystem - Dieses Modul bietet eine tragbare Möglichkeit zur Verwendung betriebssystemabhängiger Funktionen.

Für die weiteren os Funktionen ist hier die Dokumentation.

27
Peter Mortensen 28 Mai 2017 im 23:05

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()
54
Usman Khan 28 Okt. 2012 im 05:44

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
32
stuckintheshuck 10 Okt. 2014 im 17:41

Ü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')
71
Peter Mortensen 28 Mai 2017 im 23:02

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-Unterprozessschnittstelle).

Schauen Sie sich ein Beispiel an:

from sh import vgdisplay
print vgdisplay()
print vgdisplay('-v')
print vgdisplay(v=True)
71
Peter Mortensen 29 Nov. 2019 im 21:47
import os
cmd = 'ls -al'
os.system(cmd)

Wenn Sie die Ergebnisse des Befehls zurückgeben möchten, können Sie {{X0 }}. Dies ist jedoch seit Version 2.6 zugunsten des Subprozessmoduls , welche anderen Antworten gut abgedeckt haben.

136
Patrick M 26 Jän. 2016 im 16:53

Aktualisieren:

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 jedoch nicht so einfach. Siehe in dieser Frage, 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, Gesandter zu versuchen. Es ist ein Wrapper für Unterprozesse, der wiederum die älteren Module und ersetzen soll Funktionen. Gesandter ist ein Unterprozess für Menschen.

Beispiel für die Verwendung von 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'>]
52
Peter Mortensen 29 Nov. 2019 im 21:52

Ich mag shell_command wegen seiner Einfachheit sehr. 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
23
Peter Mortensen 29 Nov. 2019 im 21:49

Schamloser Stecker, 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
houqp 1 Mai 2014 im 20:49
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.

139
Peter Mortensen 3 Juni 2018 im 17:10

Verwenden Sie das OS-Modul:

import os
os.system("your command")

Beispielsweise,

import os
os.system("ifconfig")
25
Peter Mortensen 29 Nov. 2019 im 22:09

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

Überprüfen Sie den subprocess.Popen.

15
Peter Mortensen 28 Mai 2017 im 23:01

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 finden Sie hier.

34
Dimitris Fasarakis Hilliard 10 Dez. 2016 im 13:25

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 verhält sich wie os.system().

344
Trenton McKinney 4 Okt. 2019 im 02:33

Verwenden Sie den Unterprozess .

... oder für einen sehr einfachen Befehl:

import os
os.system('cat testfile')
39
Peter Mortensen 29 Nov. 2019 im 21:39

Mit os.system können Sie keine Ergebnisse speichern. Wenn Sie also Ergebnisse in einer Liste oder etwas anderem speichern möchten, funktioniert ein subprocess.call.

21
Peter Mortensen 29 Nov. 2019 im 21:48

Ohne die 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")
42
Peter Mortensen 28 Mai 2017 im 22:59