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

发布于 2024-10-20 21:06:23 字数 475 浏览 6 评论 0原文

我想编写一个运行另一个程序的 Python 脚本,读取另一个程序的输出并对其进行操作。问题是该程序提示输入密码,而我不知道如何自动提供密码。 (出于此脚本的目的,密码是否以纯文本形式存储在脚本本身中并不重要。)我想做的是:

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

这会导致某些程序给我不需要的密码提示,并且不给我程序的输出作为返回值。不幸的是,该程序没有办法绕过这个提示。

不幸的是,对于如何解决这个问题,我也有一些限制。首先,我坚持使用 Python 2.3(所以我无法使用 subprocess 模块)。其次,我无法安装任何新模块(所以没有预期)。幸运的是,它不必特别便携,因此仅 Linux 的解决方案就可以了。

我一直在试图找出 pty 模块,因为它看起来可以提供我需要的东西,但是在花了几个小时与它搏斗之后,我只是不知道如何让它按照我需要的方式工作。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

颜漓半夏 2024-10-27 21:06:23

我在基于终端的进程间通信方面遇到了一些类似的问题,这些问题似乎无法使用 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")

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")
小红帽 2024-10-27 21:06:23

您可以使用 os.popen,它已移至 subprocess 在 2.6 中,但应该仍然存在于 2.3 的 os 模块中。将模式设置为'w'并使用close()获取返回值。

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.

淡淡的优雅 2024-10-27 21:06:23

expect 还有另一个 Python 实现,可以轻松支持 pty。有一个封装 ssh 的库可以使用它发送密码。它是 Pycopia 中的 sshlib 模块。那里有一个处理密码的登录方法。它还使用 Pycopia 中的 Expect 和 process (proctools) 模块。我最初是为 Python 2.2 编写的,因此它们可能适合您。但是,它们可能不会,因为随着时间的推移,我自由地使用了 Python 的其他新功能

,这些功能可能已经悄然出现。这些模块的主要目标是使处理子流程(如您所描述的)变得更容易、更“Pythonic”。

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文