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?
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.
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.
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.
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 .
The program may be using isatty(3)
to detect presence of a tty on stdin.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With