Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does supplying stdin to subprocess.Popen cause what is written to stdout to change?

I'm using Python's subprocess.Popen to perform some FTP using the binary client of the host operating system. I can't use ftplib or any other library for various reasons.

The behavior of the binary seems to change if I attach a stdin handler to the Popen instance. For example, using XP's ftp client, which accepts a text file of commands to issue:

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

When also supplying stdin, all you get in stdout is:

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

Initially I thought this was a quirk of the XP ftp client, perhaps knowing it wasn't in interactive mode and therefore limiting its output. However, the same behaviour happens with OS X's ftp - all the server responses are missing from stdout if stdin is supplied - which leads me to think that this is normal behaviour.

In Windows I can use the -s switch to effectively script ftp without using stdin, but on other platforms one relies on the shell for that kind of interaction.

Python version is 2.6.x on both platforms. Why would supplying a handle for stdin change stdout, and where have the server responses gone to?

like image 566
Matt Avatar asked Mar 01 '10 14:03

Matt


People also ask

How does subprocess Popen work?

Popen FunctionThe function should return a pointer to a stream that may be used to read from or write to the pipe while also creating a pipe between the calling application and the executed command. Immediately after starting, the Popen function returns data, and it does not wait for the subprocess to finish.

What is stdout in Popen?

The stdout attribute of one Popen instance is used as the stdin argument for the next in the pipeline, instead of the constant PIPE. The output is read from the stdout handle for the final command in the pipeline.

What is difference between subprocess Popen and call?

Popen is more general than subprocess. call . Popen doesn't block, allowing you to interact with the process while it's running, or continue with other things in your Python program. The call to Popen returns a Popen object.

What is stdin subprocess?

By default, subprocess. run() takes stdin (standard input) from our Python program and passes it through unchanged to the subprocess. For example, on a Linux or macOS system, the cat - command outputs exactly what it receives from stdin .


1 Answers

The program may be using isatty(3) to detect presence of a tty on stdin.

like image 53
Ignacio Vazquez-Abrams Avatar answered Sep 28 '22 08:09

Ignacio Vazquez-Abrams