如何在Python中与另一个程序交互?

2 投票
3 回答
2979 浏览
提问于 2025-04-16 13:11

我想写一个Python脚本,这个脚本可以运行另一个程序,读取这个程序的输出并对其进行处理。问题是,这个程序会要求输入密码,而我不知道怎么自动输入这个密码。(对于这个脚本来说,密码如果直接写在代码里也没关系。)我想做的事情大概是这样的:

os.system('echo someinput | /var/local/bin/someprogram') 

但是这样做会导致someprogram弹出不想要的密码提示,而且也无法得到程序的输出作为返回值。可悲的是,这个程序没有办法绕过这个提示。

不幸的是,我在解决这个问题时也有一些限制。首先,我只能使用Python 2.3(所以不能使用subprocess模块)。其次,我不能安装任何新的模块(所以不能用pexpect)。幸运的是,这个解决方案不需要特别通用,所以只要在Linux上能用就可以。

我一直在尝试弄明白pty模块,因为它看起来能提供我需要的功能,但我花了几个小时研究它,还是搞不明白怎么让它按照我想要的方式工作。

3 个回答

0

还有一个Python版本的expect,它很容易支持伪终端(pty)。有一个库可以用来包裹ssh,这样就能通过它发送密码。这个库叫做sshlib模块,它是Pycopia的一部分。里面有一个登录方法,可以处理密码。这个方法还使用了Pycopia中的expect和process(proctools)模块。我最初是为Python 2.2写的,所以可能对你有用。不过,也有可能不适用,因为我在这段时间里使用了其他一些新的Python特性,这些特性可能会影响兼容性。

这些模块的主要目标是让处理子进程(比如你提到的那种情况)变得更简单,更符合Python的风格。

0

你可以使用 os.popen,这个功能在 Python 2.6 版本中被移到了 subprocess 模块,但在 2.3 版本的 os 模块里仍然可以找到。你需要把模式设置为 'w',然后用 close() 来获取返回值。

3

我在使用基于终端的进程间通信时遇到了一些类似的问题,这些问题似乎用 popen 等方法无法解决。最后,我通过阅读 pexpect 的源代码,学会了如何使用 pty,里面有很多例子和解释,告诉我如何让 pty 完成必要的操作。

当然,根据你的需求,你也可以直接 使用 pexpect!

以下是我在自己项目中用到的主要内容。请注意,我并没有检查子进程是否终止;这个脚本是为了作为一个守护进程来管理一个长时间运行的 Java 进程,所以我不需要处理状态码。不过,希望这些内容能满足你大部分的需求。

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

撰写回答