Frage

Wenn ich Folgendes tun:

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:

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'

Offenbar ein cStringIO.StringIO Objekt nahe genug nicht in eine Datei Ente quakt subprocess.Popen zu entsprechen. Wie kann ich dieses Problem umgehen?

War es hilfreich?

Lösung

Popen.communicate() Dokumentation:

  

Beachten Sie, dass, wenn Sie Daten senden möchten   der Prozess des stdin, müssen Sie   Erstellen Sie die Popen Objekt mit   stdin = PIPE. In ähnlicher Weise zu bekommen alles   anders als Keiner im Ergebnis Tupel,   Sie brauchen stdout = PIPE und / oder geben   stderr = PIPE zu.

     

Ersetzen os.popen *

    pipe = os.popen(cmd, 'w', bufsize)
    # ==>
    pipe = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE).stdin
  

Warnung Verwenden Sie kommunizieren () statt   stdin.write (), stdout.read () oder   stderr.read () Deadlocks zu vermeiden, aufgrund   zu einem der anderen OS Rohrpuffer   Auffüllen und das Kind blockiert   Prozess.

So könnte Ihr Beispiel wie folgt geschrieben werden:

from subprocess import Popen, PIPE, STDOUT

p = Popen(['grep', 'f'], stdout=PIPE, stdin=PIPE, stderr=STDOUT)    
grep_stdout = p.communicate(input=b'one\ntwo\nthree\nfour\nfive\nsix\n')[0]
print(grep_stdout.decode())
# -> four
# -> five
# ->

Auf der aktuellen Python 3-Version, können Sie subprocess.run , Eingabe als String an einen externen Befehl übergeben und ihren Exit-Status erhalten, und seine Ausgabe als String in einem Aufruf zurück:

#!/usr/bin/env python3
from subprocess import run, PIPE

p = run(['grep', 'f'], stdout=PIPE,
        input='one\ntwo\nthree\nfour\nfive\nsix\n', encoding='ascii')
print(p.returncode)
# -> 0
print(p.stdout)
# -> four
# -> five
# -> 

Andere Tipps

ich dachte, diese Abhilfe aus:

>>> p = subprocess.Popen(['grep','f'],stdout=subprocess.PIPE,stdin=subprocess.PIPE)
>>> p.stdin.write(b'one\ntwo\nthree\nfour\nfive\nsix\n') #expects a bytes type object
>>> p.communicate()[0]
'four\nfive\n'
>>> p.stdin.close()

Gibt es eine bessere?

Ich bin ein wenig überrascht, niemand vorgeschlagen, ein Rohr zu schaffen, die meiner Meinung nach ist der weit einfachste Weg, um eine Zeichenfolge zu stdin eines subprocess weitergeben müssen:

read, write = os.pipe()
os.write(write, "stdin input here")
os.close(write)

subprocess.check_call(['your-command'], stdin=read)

Es gibt eine schöne Lösung, wenn Sie verwenden Python 3.4 oder besser. Verwenden Sie das input Argument anstelle des stdin Argument, das ein Byte Argument akzeptiert:

output = subprocess.check_output(
    ["sed", "s/foo/bar/"],
    input=b"foo",
)

Ich bin mit python3 und fand heraus, dass Sie Ihre Zeichenfolge kodieren, bevor Sie es in stdin passieren kann:

p = Popen(['grep', 'f'], stdout=PIPE, stdin=PIPE, stderr=PIPE)
out, err = p.communicate(input='one\ntwo\nthree\nfour\nfive\nsix\n'.encode())
print(out)

„Anscheinend ein cStringIO.StringIO Objekt schließen sich nicht auf eine Datei Ente quaken genug subprocess.Popen passen“

: -)

Ich fürchte nicht. Das Rohr ist ein Low-Level-OS Konzept, so dass es erfordert unbedingt ein Datei-Objekt, das von einer OS-Ebene Dateideskriptors dargestellt wird. Ihre Abhilfe ist, die richtige ist.

from subprocess import Popen, PIPE
from tempfile import SpooledTemporaryFile as tempfile
f = tempfile()
f.write('one\ntwo\nthree\nfour\nfive\nsix\n')
f.seek(0)
print Popen(['/bin/grep','f'],stdout=PIPE,stdin=f).stdout.read()
f.close()
"""
Ex: Dialog (2-way) with a Popen()
"""

p = subprocess.Popen('Your Command Here',
                 stdout=subprocess.PIPE,
                 stderr=subprocess.STDOUT,
                 stdin=PIPE,
                 shell=True,
                 bufsize=0)
p.stdin.write('START\n')
out = p.stdout.readline()
while out:
  line = out
  line = line.rstrip("\n")

  if "WHATEVER1" in line:
      pr = 1
      p.stdin.write('DO 1\n')
      out = p.stdout.readline()
      continue

  if "WHATEVER2" in line:
      pr = 2
      p.stdin.write('DO 2\n')
      out = p.stdout.readline()
      continue
"""
..........
"""

out = p.stdout.readline()

p.wait()

Beachten Sie, dass Popen.communicate(input=s)may Sie Probleme geben ifsis zu groß, denn anscheinend wird der übergeordnete Prozess es Puffer vor das Kind subprocess gabeln, was bedeutet, es an diesem Punkt „doppelt so viel“ gebrauchte Speicher benötigt (mindestens nach der „unter der Haube“ Erklärung und verknüpfte Dokumentation ). In meinem speziellen Fall swas einen Generator, die ersten voll ausgebaut wurde und erst dann geschrieben tostdin so der übergeordnete Prozess riesig richtig war, bevor das Kind hervorgebracht wurde, und kein Speicher übrig war, um es zu Gabel:

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

p = Popen(['grep', 'f'], stdout=PIPE, stdin=PIPE, stderr=STDOUT)    
p.stdin.write('one\n')
time.sleep(0.5)
p.stdin.write('two\n')
time.sleep(0.5)
p.stdin.write('three\n')
time.sleep(0.5)
testresult = p.communicate()[0]
time.sleep(0.5)
print(testresult)
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top