Wenn ich folgendes mache:
import subprocess
from cStringIO import StringIO
subprocess.Popen(['grep','f'],stdout=subprocess.PIPE,stdin=StringIO('one\ntwo\nthree\nfour\nfive\nsix\n')).communicate()[0]
Ich bekomme:
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "/build/toolchain/mac32/python-2.4.3/lib/python2.4/subprocess.py", line 533, in __init__
(p2cread, p2cwrite,
File "/build/toolchain/mac32/python-2.4.3/lib/python2.4/subprocess.py", line 830, in _get_handles
p2cread = stdin.fileno()
AttributeError: 'cStringIO.StringI' object has no attribute 'fileno'
Anscheinend quakt ein cStringIO.StringIO-Objekt nicht nahe genug an einer Dateiente, um dem Unterprozess zu entsprechen. Wie kann ich das umgehen?
python
subprocess
stdin
Daryl Spitzer
quelle
quelle
call(['ls', '-1'], shell=True)
ist falsch. Ich empfehle stattdessen, häufig gestellte Fragen aus der Tag-Beschreibung des Unterprozesses zu lesen . Insbesondere, warum subprocess.Popen nicht funktioniert, wenn args eine Sequenz ist? erklärt warumcall(['ls', '-1'], shell=True)
ist falsch. Ich erinnere mich, dass ich Kommentare unter dem Blog-Beitrag hinterlassen habe, aber ich sehe sie jetzt aus irgendeinem Grund nicht.subprocess.run
siehe stackoverflow.com/questions/48752152/…Antworten:
Popen.communicate()
Dokumentation:Ihr Beispiel könnte also wie folgt geschrieben werden:
In der aktuellen Python 3-Version können Sie die
subprocess.run
Eingabe als Zeichenfolge an einen externen Befehl übergeben und den Beendigungsstatus sowie die Ausgabe als Zeichenfolge in einem Aufruf zurückerhalten:quelle
Ich habe diese Problemumgehung herausgefunden:
Gibt es einen besseren?
quelle
stdin.write()
Verwendung wird nicht empfohlen ,p.communicate()
sollte verwendet werden. Siehe meine Antwort.communicate
wird die Pipe geschlossen und der Prozess kann ordnungsgemäß beendet werden.read()
davon, wiecommunicate()
auch ohne Argumente).Ich bin ein bisschen überrascht, dass niemand vorgeschlagen hat, eine Pipe zu erstellen. Dies ist meiner Meinung nach der einfachste Weg, eine Zeichenfolge an stdin eines Unterprozesses zu übergeben:
quelle
os
als auch diesubprocess
Dokumentation stimmen darin überein, dass Sie die letztere der ersteren vorziehen sollten. Dies ist eine Legacy-Lösung mit einem (etwas weniger präzisen) Standardersatz. Die akzeptierte Antwort zitiert die einschlägige Dokumentation.Es gibt eine schöne Lösung, wenn Sie Python 3.4 oder besser verwenden. Verwenden Sie das
input
Argument anstelle desstdin
Arguments, das ein Byte-Argument akzeptiert:Dies funktioniert für
check_output
undrun
, aber nichtcall
odercheck_call
aus irgendeinem Grund.quelle
check_output
ich eininput
Argument haben sollte, aber nichtcall
.check_call
aber es funktioniert fürrun
. Es funktioniert auch mit input = string, solange Sie gemäß der Dokumentation auch ein Codierungsargument übergeben.Ich verwende python3 und habe herausgefunden, dass Sie Ihren String codieren müssen, bevor Sie ihn an stdin übergeben können:
quelle
b'something'
. B. ). Es wird err und out auch als Bytes zurückgeben. Wenn Sie dies vermeiden möchten, können Sieuniversal_newlines=True
an übergebenPopen
. Dann akzeptiert es die Eingabe als str und gibt err / out auch als str zurück.universal_newlines=True
konvertieren Sie auch Ihre Zeilenumbrüche, um sie an Ihr System anzupassenIch fürchte nein. Die Pipe ist ein Betriebssystemkonzept auf niedriger Ebene, daher ist unbedingt ein Dateiobjekt erforderlich, das durch einen Dateideskriptor auf Betriebssystemebene dargestellt wird. Ihre Problemumgehung ist die richtige.
quelle
quelle
Beachten Sie, dass dies zu
Popen.communicate(input=s)
Problemen führen kann, wenns
es zu groß ist, da der übergeordnete Prozess es anscheinend puffert, bevor der untergeordnete Unterprozess gegabelt wird. Dies bedeutet, dass zu diesem Zeitpunkt "doppelt so viel" Speicher benötigt wird (zumindest gemäß der Erklärung "unter der Haube") und verknüpfte Dokumentation finden Sie hier ). In meinem speziellen Fall handeltes
es sich um einen Generator, der zuerst vollständig erweitert und erst dann beschrieben wurde,stdin
sodass der übergeordnete Prozess unmittelbar vor dem Laichen des Kindes sehr umfangreich war und kein Speicher mehr vorhanden war, um ihn zu teilen:File "/opt/local/stow/python-2.7.2/lib/python2.7/subprocess.py", line 1130, in _execute_child self.pid = os.fork() OSError: [Errno 12] Cannot allocate memory
quelle
quelle
shell=True
so häufig ohne guten Grund verwendet wird und dies eine beliebte Frage ist, möchte ich darauf hinweisen, dass es viele Situationen gibt, in denenPopen(['cmd', 'with', 'args'])
es entschieden besser ist alsPopen('cmd with args', shell=True)
und wenn die Shell den Befehl und die Argumente in Token zerlegt, aber ansonsten nichts bereitstellt nützlich, während eine erhebliche Menge an Komplexität hinzugefügt wird und somit auch die Oberfläche angreift.quelle
Gehen Sie unter Python 3.7+ folgendermaßen vor:
und Sie möchten wahrscheinlich hinzufügen
capture_output=True
, um die Ausgabe des Ausführens des Befehls als Zeichenfolge zu erhalten.Ersetzen Sie in älteren Versionen von Python Folgendes
text=True
durchuniversal_newlines=True
:quelle