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.run
consulte 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.communicate
cerrará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
os
y lasubprocess
documentació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
input
argumento en lugar delstdin
argumento, que acepta un argumento de bytes:Esto funciona para
check_output
yrun
, pero nocall
ocheck_call
por alguna razón.fuente
check_output
deba tener unainput
discusión, pero nocall
.check_call
pero 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=True
aPopen
. Entonces aceptará la entrada como str y devolverá err / out como str también.universal_newlines=True
tambié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 sis
es 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,s
fue un generador que primero se expandió por completo y solo luego se escribió parastdin
que 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 memory
fuente
fuente
shell=True
que 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=True
para obtener el resultado de ejecutar el comando como una cadena.En versiones anteriores de Python, reemplace
text=True
conuniversal_newlines=True
:fuente