How can I interact with another program in Python?
I want to write a Python script that runs another program, reading the output of the other program and manipulating it. The problem is that this program prompts for a password, and I cannot figure out how to supply it automatically. (For the purposes of this script, it really does not matter if the password is stored in plain-text in the script itself.) What I want to do is something like:
os.system('echo someinput | /var/local/bin/someprogram')
Which results in someprogram giving me the unwanted password prompt, and also doesn't give me the program's output as the return value. Tragically, the program does not have a way to bypass this prompt.
Unfortunately, I also have some restrictions as to how I can go about solving this problem. First, I'm stuck with Python 2.3 (so I cannot use the subprocess module). Second,开发者_开发百科 I cannot install any new modules, (so no pexpect). Fortunately, it doesn't have to be particularly portable, so a Linux-only solution is fine.
I've been trying to figure out the pty module, since it looks like it offers what I need, but after spending hours wrestling with it, I just cannot figure out how to get it to work the way I need it to.
I had some similar problems with terminal-based interprocess communication that didn't seem to be solvable using popen
(et al.). I ended up learning how to use pty
by reading the source of pexpect, which contains examples of how (and comments of why) to get pty
to jump through the necessary hoops.
Depending on your needs, of course, you could also just use pexpect!
Here's the meat of what I used in my own project. Note that I'm not checking to see whether the child process terminates; the script was intended to run as a daemon managing a long-running Java process, so I never had to deal with status codes. Hopefully, this will get you most of what you need, however.
import os
import pty
import select
import termios
child_pid, child_fd = pty.fork()
if not child_pid: # child process
os.execv("/path/to/command", ["command", "arg1", "arg2"])
# disable echo
attr = termios.tcgetattr(child_fd)
attr[3] = attr[3] & ~termios.ECHO
termios.tcsetattr(child_fd, termios.TCSANOW, attr)
while True:
# check whether child terminal has output to read
ready, _, _ = select.select([child_fd], [], [])
if child_fd in ready:
output = []
try:
while True:
s = os.read(child_fd, 1)
# EOF or EOL
if not s or s == "\n":
break
# don't store carriage returns (no universal line endings)
if not s == "\r":
output.append(s)
except OSError: # this signals EOF on some platforms
pass
if output.find("Enter password:") > -1:
os.write(child_fd, "password")
You can use os.popen, which was moved to subprocess
in 2.6 but should still exist in 2.3's os
module. Set the mode to 'w'
and use close()
to get the return value.
There is also another Python implementation of expect
, that easily supports pty's. There is a library that wraps ssh that can send passwords using it. It's the sshlib module in Pycopia. There is a login method there that handles passwords. It uses the expect and process (proctools) modules from Pycopia as well. I originally wrote them for Python 2.2, so they may work for you. But then, they may not since I've freely used other new features Python over time that may have crept in.
The primary goal of those modules was to make dealing with subprocesses, such as you describe, easier and more "Pythonic".
精彩评论