2010-03-01 6 views
6

Ich benutze Pythons subprocess.Popen, um einige FTP mit dem binären Client des Host-Betriebssystems durchzuführen. Ich kann ftplib oder irgendeine andere Bibliothek aus verschiedenen Gründen nicht verwenden.Warum verursacht das Zuführen von stdin zu subprocess.Popen, was in stdout geschrieben wird, um zu ändern?

Das Verhalten der Binärdatei scheint sich zu ändern, wenn ich einen stdin-Handler an die Popen-Instanz anschließe. Zum Beispiel mit XP FTP-Client, der eine Textdatei von Befehlen ausgegeben werden akzeptiert:

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

Wenn auch stdin liefert alles, was Sie in stdout erhalten ist:

Ursprünglich dachte ich, das sei eine Eigenart des XP FTP Clients, vielleicht wissend, dass es nicht im interaktiven Modus war und daher die Ausgabe limitierte. Dasselbe Verhalten tritt jedoch bei OS Xs ftp auf - alle Server-Antworten fehlen in stdout, wenn stdin angegeben wird - was mich zu der Annahme verleitet, dass dies ein normales Verhalten ist.

In Windows kann ich verwenden Sie die Option -s, um effektiv zu schreiben FTP ohne stdin, aber auf anderen Plattformen stützt man sich auf die Shell für diese Art von Interaktion.

Python-Version ist 2.6.x auf beiden Plattformen. Warum sollte ein Handle für stdin die stdout ändern und wo sind die Antworten des Servers hin?

+0

Haben Sie erwogen, 'ftplib' zu verwenden? http://docs.python.org/library/ftplib.html –

+0

aus welchen Gründen können Sie ftplib nicht verwenden. Es kommt mit Ihrem Python-Vertriebsrecht? – ghostdog74

Antwort

4

Ich glaube, ich habe irgendwo gelesen (kann mich aber nicht erinnern, wo), dass Windows-FTP-Client von einer der ursprünglichen BSD-Implementierungen kam. Darin würde sicherlich eine gewisse Verwandtschaft mit der FTP-Implementierung von Mac OS X bestehen.

Für mich hängt dies nicht mit Popen zusammen, sondern mit der Client-FTP-Programmimplementierung, die mit issatty einige Überprüfungen des Kontextes durchführt, in dem es gestartet wird (um zu sehen, ob es mit einem menschlichen oder einem Shell-Skript interagiert) (3) wie mit Ignacio in seiner Antwort erwähnt. Dies ist gängige Praxis für Programme, die in beiden Kontexten verwendet werden können. Ein bekanntes Beispiel ist die GNU-Implementierung von grep für die Option --color = auto: Die Ausgabe wird nur dann coloriert, wenn stdout ein tty ist, und nicht, wenn die Ausgabe von grep an einen anderen Befehl übergeben wird.

+0

Ja, ich denke du hast Recht damit. Wenn ich den Arbeitscode als Windows-Dienst ausführe (der auch eine nicht-interaktive Standardeingabe hat), bekomme ich das gleiche Verhalten. Die Folgefrage ist also - gibt es einen plattformübergreifenden Weg, die ausführbare Datei zu "tricksen", mit der sie spricht? Ich gehe davon aus, dass es keine Features eines tty benötigt, um die volle Ausgabe zu produzieren. – Matt

+0

Nicht, dass ich davon weiß. Beachten Sie jedoch, dass es keinen standardmäßigen plattformübergreifenden ftp-Befehl mit einer einheitlichen Schnittstelle (z. B. Befehlszeilenargumente) gibt, so dass es Ihnen schwer fällt, mit diesem Ansatz portablen Code zu schreiben. Wenn Ihr Skript braucht nur ein paar Dateien mit FTP zum Download, Ich empfehle, mit urllib oder urllib2: Import urllib f = urllib.urlopen ('ftp://example.com/testfiles/100.KiB') data = f.read() –

+0

Ich verbrachte einige Zeit experimentieren mit Pexpect/wexpect, die eine einigermaßen plattformunabhängige Lösung versprach.Leider benötigt wexpect eine Konsole und stirbt schrecklich, wenn es als Windows-Dienst ausgeführt wird. – Matt

7

Das Programm verwendet möglicherweise isatty(3), um das Vorhandensein eines tty auf stdin zu erkennen.