2010-03-01 12 views
6

Estoy usando el subproceso de Python. Tengo permiso para realizar algunos FTP utilizando el cliente binario del sistema operativo host. No puedo usar ftplib o cualquier otra biblioteca por varias razones.¿Por qué el suministro de stdin al subproceso.Popen hace que cambie lo que está escrito en stdout?

El comportamiento del binario parece cambiar si adjunto un controlador stdin a la instancia de Popen. Por ejemplo, usando el cliente FTP de XP, que acepta un archivo de texto de los comandos de edición:

>>>from subprocess import Popen, PIPE 
>>>p = Popen(['ftp','-A','-s:commands.txt','example.com'], stdout=PIPE) 
>>>p.communicate()[0] 
'Connected to example.com. 
220 ProFTPD 1.3.1 Server (Debian) ... 
331 Anonymous login ok, send your complete email address as your password 
<snip> 
ftp> binary 
200 Type set to I 
ftp> get /testfiles/100.KiB 
200 PORT command successful 
150 Opening BINARY mode data connection for /testfiles/100.KiB (102400 bytes) 
226 Transfer complete 
ftp: 102400 bytes received in 0.28Seconds 365.71Kbytes/sec. 
ftp> quit 
>>> 

commands.txt:

binary 
get /testfiles/100.KiB 
quit 

Cuando también el suministro de la entrada estándar, todo lo que obtiene en la salida estándar es:

>>>from subprocess import Popen, PIPE 
>>>p = Popen(['ftp','-A','-s:commands.txt','example.com'], stdin=PIPE, stdout=PIPE) 
>>>p.communicate()[0] 
'binary 
get /testfiles/100.KiB 
quit' 
>>> 

Inicialmente pensé que esto era un capricho del cliente de ftp XP, quizás sabiendo que no estaba en modo interactivo y, por lo tanto, limitando su salida. Sin embargo, el mismo comportamiento ocurre con el ftp de OS X. Todas las respuestas del servidor faltan en stdout si se proporciona stdin, lo que me lleva a pensar que esto es un comportamiento normal.

En Windows puedo usar el modificador -s para guiar eficazmente ftp sin usar stdin, pero en otras plataformas uno se basa en el shell para ese tipo de interacción.

La versión de Python es 2.6.x en ambas plataformas. ¿Por qué el suministro de un controlador para stdin cambiar stdout, y donde han ido las respuestas del servidor?

+0

¿Ha considerado usar 'ftplib'? http://docs.python.org/library/ftplib.html –

+0

cuáles son las razones por las que no puedes usar ftplib. viene con tu distribución Python ¿verdad? – ghostdog74

Respuesta

4

Creo que he leído en alguna parte (pero no recuerdo dónde) que el cliente ftp de Windows proviene de una de las implementaciones originales de BSD. En eso ciertamente compartiría alguna relación con la implementación ftp de Mac OS X.

Para mí, esto no está relacionado con Popen sino con la implementación del programa ftp cliente, que hace algunas comprobaciones sobre el contexto en el que se inicia (para ver si está interactuando con un script humano o de shell), usando isatty (3) como se menciona con Ignacio en su respuesta. Esta es una práctica común para los programas que se pueden usar en ambos contextos. Un ejemplo bien conocido es la implementación grep de GNU para la opción --color = auto: coloreará la salida solo si stdout es un tty, y no si la salida de grep se canaliza a otro comando.

+0

Sí, creo que tienes razón sobre esto. Cuando ejecuto el código de trabajo como un servicio de Windows (que también tiene un stdin no interactivo) obtengo el mismo comportamiento. Entonces, la siguiente pregunta es: ¿hay una forma de "engañar" el ejecutable multiplataforma que está hablando con un tty? Supongo que en realidad no necesita ninguna característica de un tty para producir la salida completa. – Matt

+0

No es que yo sepa. Sin embargo, tenga en cuenta que no existe un comando ftp multiplataforma estándar con una interfaz unificada (es decir, argumentos de línea de comandos), por lo que tendrá dificultades para escribir código portátil con este enfoque. Si el script sólo tiene que descargar un par de archivos a través de FTP, recomiendo el uso de urllib o urllib2: importación urllib f = urllib.urlopen ('ftp://example.com/testfiles/100.KiB') data = f.read() –

+0

Pasé algún tiempo experimentando con pexpect/wexpect, que prometía ser una solución razonablemente independiente de la plataforma.Lamentablemente Wexpect necesita una consola y muere horriblemente cuando se ejecuta como un servicio de Windows. – Matt

7

El programa puede estar utilizando isatty(3) para detectar la presencia de un tty en stdin.

Cuestiones relacionadas