如何与Python中的其他程序交互?

时间:2022-06-19 23:46:20

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:

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

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.

不幸的是,对于如何解决这个问题,我也有一些限制。首先,我使用的是Python 2.3(因此我不能使用子流程模块)。其次,我不能安装任何新的模块(所以没有pexpect)。幸运的是,它不需要特别的便携,所以只有linux的解决方案是可以的。

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.

我一直在尝试找出pty模块,因为它看起来提供了我所需要的东西,但是在花了几个小时的时间研究它之后,我就是想不出如何让它以我需要的方式工作。

3 个解决方案

#1


3  

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.

我在基于终端的进程间通信中遇到了一些类似的问题,这些问题似乎不能通过popen(等人)来解决。最后,我通过阅读pexpect的源代码了解了如何使用pty,其中包含了如何(以及为什么)让pty跨越必要的限制的示例。

Depending on your needs, of course, you could also just use pexpect!

当然,根据您的需要,您也可以使用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.

这是我在自己的项目中使用的精华。注意,我没有检查子进程是否终止;该脚本的目的是作为管理长期运行的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")

#2


0  

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.

您可以使用操作系统。popen在2.6中被转移到子进程,但是仍然存在于2.3的os模块中。将模式设置为'w'并使用close()获取返回值。

#3


0  

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.

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

The primary goal of those modules was to make dealing with subprocesses, such as you describe, easier and more "Pythonic".

这些模块的主要目标是使处理子进程(如您所描述的)变得更容易和更“python化”。

#1


3  

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.

我在基于终端的进程间通信中遇到了一些类似的问题,这些问题似乎不能通过popen(等人)来解决。最后,我通过阅读pexpect的源代码了解了如何使用pty,其中包含了如何(以及为什么)让pty跨越必要的限制的示例。

Depending on your needs, of course, you could also just use pexpect!

当然,根据您的需要,您也可以使用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.

这是我在自己的项目中使用的精华。注意,我没有检查子进程是否终止;该脚本的目的是作为管理长期运行的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")

#2


0  

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.

您可以使用操作系统。popen在2.6中被转移到子进程,但是仍然存在于2.3的os模块中。将模式设置为'w'并使用close()获取返回值。

#3


0  

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.

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

The primary goal of those modules was to make dealing with subprocesses, such as you describe, easier and more "Pythonic".

这些模块的主要目标是使处理子进程(如您所描述的)变得更容易和更“python化”。