Wie rufe ich einen externen Befehl in Python auf, als hätte ich ihn in einer Shell oder Eingabeaufforderung eingegeben?
Deadlock-Potenzial: Verwenden Sie die .communicate
Methode stattdessen
Wie rufe ich einen externen Befehl in Python auf, als hätte ich ihn in einer Shell oder Eingabeaufforderung eingegeben?
Hier sind meine zwei Cents: Meiner Meinung nach ist dies die beste Vorgehensweise im Umgang mit externen Befehlen...
Dies sind die Rückgabewerte der Methode execute...
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]
Ich habe eine kleine Bibliothek geschrieben, die bei diesem Anwendungsfall hilft:
https://pypi.org/project/citizenshell/
Es kann installiert werden mit
pip install citizenshell
Und dann wie folgt verwendet:
from citizenshell import sh
assert sh("echo Hello World") == "Hello World"
Sie können die Standardausgabe von der Standardfehlerausgabe 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 der Clou 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, sobald sie verfügbar sind, dank der Option 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
Nur um die Diskussion zu ergänzen: Wenn Sie eine Python-Konsole verwenden, können Sie externe Befehle von IPython . In der IPython-Eingabeaufforderung können Sie Shell-Befehle aufrufen, indem Sie '!' voranstellen. Sie können auch Python-Code mit der Shell kombinieren und die Ausgabe von Shell-Skripten an Python-Variablen zuweisen.
Zum Beispiel:
In [9]: mylist = !ls
In [10]: mylist
Out[10]:
['file1',
'file2',
'file3',]
Aufrufen eines externen Befehls in Python
Ein einfacher Weg, einen externen Befehl aufzurufen, ist die Verwendung von os.system(...)
. Und diese Funktion gibt den Exit-Wert des Befehls zurück. Aber der Nachteil ist, dass wir stdout und stderr nicht erhalten werden.
ret = os.system('some_cmd.sh')
if ret != 0 :
print 'some_cmd.sh execution returned failure'
Aufrufen 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 abrufen.
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
Aufrufen eines lang laufenden externen Befehls in Python im Hintergrund und Anhalten nach einiger Zeit
Wir können sogar einen lang laufenden Prozess im Hintergrund starten, indem wir subprocess.Popen
und beenden Sie ihn nach einiger Zeit, wenn 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]
Verwendung:
import subprocess
p = subprocess.Popen("df -h", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
print p.split("\n")
Es gibt eine schöne Ausgabe, mit der man besser arbeiten kann:
['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',
'']
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.
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 mitimport subprocess; subprocess.run(["ls", "-l"])
.