一尘不染

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

python

我正在使用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开关来有效地编写ftp脚本,而无需使用stdin,但是在其他平台上,这种交互取决于外壳程序。

在两个平台上,Python版本均为2.6.x。为什么为stdin提供句柄会更改stdout,并且服务器响应会发送到哪里?


阅读 203

收藏
2021-01-20

共1个答案

一尘不染

我想我在某个地方(但不记得在哪里)读到Windows ftp客户端来自原始BSD实现之一。这样肯定会与Mac OS X的ftp实现共享一些关系。

对我而言,这与Popen无关,而与客户端ftp程序实现有关,后者使用isatty(3)作为启动程序的启动上下文进行检查(以查看它是与人类脚本还是与Shell脚本交互)。在回答中提到了伊格纳西奥。对于可以在两种情况下使用的程序,这都是惯例。一个著名的示例是
–color = auto选项的GNU
grep实现:仅当stdout是tty时,它才会着色输出,而如果grep的输出通过管道传递到另一个命令中,则不会着色。

2021-01-20