¿Cómo paso una cadena al subproceso.Popen (usando el argumento stdin)?

Resuelto Daryl Spitzer asked hace 15 años • 12 respuestas

Si hago lo siguiente:

import subprocess
from cStringIO import StringIO
subprocess.Popen(['grep','f'],stdout=subprocess.PIPE,stdin=StringIO('one\ntwo\nthree\nfour\nfive\nsix\n')).communicate()[0]

Yo obtengo:

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'

Aparentemente, un objeto cStringIO.StringIO no grazna lo suficientemente cerca de un archivo pato para adaptarse al subproceso.Popen. ¿Cómo soluciono esto?

Daryl Spitzer avatar Oct 03 '08 00:10 Daryl Spitzer
Aceptado

Popen.communicate()documentación:

Tenga en cuenta que si desea enviar datos a la entrada estándar del proceso, debe crear el objeto Popen con stdin=PIPE. De manera similar, para obtener algo más que Ninguno en la tupla de resultados, también debe ingresar stdout=PIPE y/o stderr=PIPE.

Reemplazo de os.popen*

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

Advertencia Utilice comunicar() en lugar de stdin.write(), stdout.read() o stderr.read() para evitar interbloqueos debido a que cualquiera de los otros buffers de canalización del sistema operativo se llene y bloquee el proceso secundario.

Entonces su ejemplo podría escribirse de la siguiente manera:

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

En Python 3.5+ (3.6+ para encoding), puede usar subprocess.run, para pasar la entrada como una cadena a un comando externo y obtener su estado de salida y su salida como una cadena en una sola llamada:

#!/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
# -> 
jfs avatar Oct 03 '2008 04:10 jfs

Descubrí esta solución:

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

Hay alguno mejor?

Daryl Spitzer avatar Oct 02 '2008 17:10 Daryl Spitzer