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 se acerca lo suficientemente cerca de un archivo duck como para adaptarse al subproceso. ¿Cómo evito esto?
python
subprocess
stdin
Daryl Spitzer
fuente
fuente

call(['ls', '-1'], shell=True)es incorrecto. En su lugar, recomiendo leer preguntas comunes de la descripción de la etiqueta del subproceso . En particular, ¿Por qué el subproceso.Popen no funciona cuando args es secuencia? explica por quécall(['ls', '-1'], shell=True)está mal Recuerdo haber dejado comentarios debajo de la publicación del blog, pero no los veo ahora por alguna razón.subprocess.runconsulte stackoverflow.com/questions/48752152/…Respuestas:
Popen.communicate()documentación:Entonces su ejemplo podría escribirse de la siguiente manera:
En la versión actual de Python 3, 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 de nuevo en una llamada:fuente
Descubrí esta solución alternativa:
Hay alguno mejor?
fuente
stdin.write()se desaconseja el uso,p.communicate()debe usarse. Mira mi respuesta.communicatecerrarán la tubería y permitirán que el proceso finalice con gracia.read(),communicate()incluso sin argumentos).Estoy un poco sorprendido de que nadie haya sugerido crear una tubería, que en mi opinión es la forma más simple de pasar una cadena a stdin de un subproceso:
fuente
osy lasubprocessdocumentación coinciden en que debe preferir lo último a lo primero. Esta es una solución heredada que tiene un reemplazo estándar (un poco menos conciso); la respuesta aceptada cita la documentación pertinente.Hay una solución hermosa si estás usando Python 3.4 o mejor. Use el
inputargumento en lugar delstdinargumento, que acepta un argumento de bytes:Esto funciona para
check_outputyrun, pero nocallocheck_callpor alguna razón.fuente
check_outputdeba tener unainputdiscusión, pero nocall.check_callpero funcionarun. También funciona con input = string siempre que pase un argumento de codificación también de acuerdo con la documentación.Estoy usando python3 y descubrí que necesitas codificar tu cadena antes de poder pasarla a stdin:
fuente
b'something'). Devolverá err y out como bytes también. Si desea evitar esto, puede pasaruniversal_newlines=TrueaPopen. Entonces aceptará la entrada como str y devolverá err / out como str también.universal_newlines=Truetambién convertirá sus nuevas líneas para que coincidan con su sistemaMe temo que no. La canalización es un concepto de sistema operativo de bajo nivel, por lo que requiere absolutamente un objeto de archivo que esté representado por un descriptor de archivo de nivel de sistema operativo. Su solución es la correcta.
fuente
fuente
Tenga en cuenta que
Popen.communicate(input=s)puede causarle problemas sises demasiado grande, porque aparentemente el proceso principal lo amortiguará antes de bifurcar el subproceso secundario, lo que significa que necesita "el doble" de memoria usada en ese momento (al menos de acuerdo con la explicación "bajo el capó" y documentación vinculada que se encuentra aquí ). En mi caso particular,sfue un generador que primero se expandió por completo y solo luego se escribió parastdinque el proceso principal fuera enorme justo antes de que se generara el hijo, y no quedara memoria para bifurcarlo: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 memoryfuente
fuente
shell=Trueque se usa tan comúnmente sin una buena razón, y esta es una pregunta popular, permítanme señalar que hay muchas situaciones en las quePopen(['cmd', 'with', 'args'])es decididamente mejor quePopen('cmd with args', shell=True)hacer que el shell rompa el comando y los argumentos en tokens, pero no proporcione nada útil, al tiempo que agrega una cantidad significativa de complejidad y, por lo tanto, también ataca la superficie.fuente
En Python 3.7+ haz esto:
y probablemente desee agregar
capture_output=Truepara obtener el resultado de ejecutar el comando como una cadena.En versiones anteriores de Python, reemplace
text=Trueconuniversal_newlines=True:fuente