我正在使用Python的subprocess.Popen来使用主机操作系统的二进制客户端执行一些FTP。由于各种原因,我无法使用ftplib或任何其他库。
如果我将stdin处理程序附加到Popen实例,则二进制文件的行为似乎会改变。例如,使用XP的ftp客户端,它接受发出命令的文本文件:
>>>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
当还提供stdin时,stdout中的所有内容都是:
>>>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'
>>>
最初我认为这是XP ftp客户端的一个怪癖,也许知道它不是处于交互模式,因此限制了它的输出。但是,OS X的ftp也会出现相同的行为 - 如果提供stdin,则stdout中缺少所有服务器响应 - 这使我认为这是正常行为。
在Windows中,我可以使用-s开关在不使用stdin的情况下有效编写ftp脚本,但在其他平台上,依赖于shell进行这种交互。
两个平台上的Python版本都是2.6.x.为什么提供stdin的句柄改变stdout,服务器响应去哪里?
答案 0 :(得分:7)
该程序可能正在使用isatty(3)
来检测stdin上是否存在tty。
答案 1 :(得分:4)
我想我在某个地方(但不记得在哪里)读到了Windows ftp客户端来自原始BSD实现之一。因为它肯定与Mac OS X的ftp实现有一些关系。
对我来说,这与Popen无关,而是与客户端ftp程序实现有关,它使用isatty(对其启动的上下文进行一些检查(以查看它是否与人类或shell脚本交互)) 3)正如伊格纳西奥在回答中提到的那样。这是可以在两种情况下使用的程序的常见做法。一个众所周知的例子是--color = auto选项的GNU grep实现:只有当stdout是tty时它才会着色输出,而不是grep的输出被管道输入另一个命令。