为什么将stdin提供给subprocess.Popen会导致写入stdout的内容发生变化?

Mat*_*att 6 python stdin subprocess stdout popen

我正在使用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  
>>>
Run Code Online (Sandbox Code Playgroud)

commands.txt中:

binary  
get /testfiles/100.KiB  
quit  
Run Code Online (Sandbox Code Playgroud)

当还提供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'  
>>>
Run Code Online (Sandbox Code Playgroud)

最初我认为这是XP ftp客户端的一个怪癖,也许知道它不是处于交互模式,因此限制了它的输出.但是,OS X的ftp也会出现相同的行为 - 如果提供stdin,则stdout中缺少所有服务器响应 - 这使我认为这是正常行为.

在Windows中,我可以使用-s开关在不使用stdin的情况下有效地编写ftp脚本,但在其他平台上,依赖shell进行这种交互.

两个平台上的Python版本都是2.6.x. 为什么提供stdin的句柄改变stdout,以及服务器响应去哪里?

Ign*_*ams 7

该程序可isatty(3)用于检测stdin上tty的存在.


gur*_*lex 4

我想我在某处读到(但不记得在哪里)Windows ftp 客户端来自原始的 BSD 实现之一。因为它肯定与 Mac OS X 的 ftp 实现有一些关系。

对我来说,这与 Popen 无关,而是与客户端 ftp 程序实现相关,客户端 ftp 程序实现会对其启动的上下文进行一些检查(以查看它是否与人类或 shell 脚本交互),使用 isatty(3) 作为伊格纳西奥在他的回答中提到。对于可以在两种情况下使用的程序来说,这是常见的做法。一个众所周知的例子是 GNU grep 实现 --color=auto 选项:只有当 stdout 是 tty 时,它才会对输出进行着色,而当 grep 的输出通过管道传输到另一个命令时则不会。