python 使用 Popen.stdin 执行多个命令

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2161575/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 23:56:33  来源:igfitidea点击:

Executing multiple commands using Popen.stdin

pythonpopen

提问by sz.

I'd like to execute multiple commands in a standalone application launched from a python script, using pipes. The only way I could reliably pass the commands to the stdin of the program was using Popen.communicate but it closes the program after the command gets executed. If I use Popen.stdin.write than the command executes only 1 time out of 5 or so, it does not work reliable. What am I doing wrong?

我想使用管道在从 python 脚本启动的独立应用程序中执行多个命令。我可以可靠地将命令传递给程序的标准输入的唯一方法是使用 Popen.communicate 但它在命令执行后关闭程序。如果我使用 Popen.stdin.write 比命令只执行大约 5 次中的 1 次,它就不能可靠地工作。我究竟做错了什么?

To elaborate a bit :

详细说明一下:

I have an application that listens to stdin for commands and executes them line by line. I'd like to be able to run the application and pass various commands to it, based on the users interaction with a GUI. This is a simple test example:

我有一个应用程序,它监听 stdin 的命令并逐行执行它们。我希望能够根据用户与 GUI 的交互运行该应用程序并向其传递各种命令。这是一个简单的测试示例:

import os, string
from subprocess import Popen, PIPE

command = "anApplication" 
process = Popen(command, shell=False, stderr=None, stdin=PIPE)

process.stdin.write("doSomething1\n")
process.stdin.flush()
process.stdin.write("doSomething2\n")
process.stdin.flush()

I'd expect to see the result of both commands but I don't get any response. (If I execute one of the Popen.write lines multiple times it occasionally works.)

我希望看到两个命令的结果,但我没有得到任何响应。(如果我多次执行 Popen.write 行之一,它偶尔会起作用。)

And if I execute:

如果我执行:

process.communicate("doSomething1")

it works perfectly but the application terminates.

它运行良好,但应用程序终止。

回答by sz.

If I understand your problem correctly, you want to interact (i.e. send commands and read the responses) with a console application.

如果我正确理解您的问题,您希望与控制台应用程序交互(即发送命令和读取响应)。

If so, you may want to check an Expect-like library, like pexpect for Python: http://pexpect.sourceforge.net

如果是这样,您可能需要检查一个类似 Expect 的库,例如 Python 的 pexpect:http://pexpect.sourceforge.net

It will make your life easier, because it will take care of synchronization, the problem that ddaa also describes. See also: http://www.noah.org/wiki/Pexpect#Q:_Why_not_just_use_a_pipe_.28popen.28.29.29.3F

它会让你的生活更轻松,因为它会处理同步,ddaa 也描述了这个问题。另见:http: //www.noah.org/wiki/Pexpect#Q: _Why_not_just_use_a_pipe_.28popen.28.29.29.3F

回答by holdenweb

The real issue here is whether the application is buffering its output, and if it is whether there's anything you can do to stop it. Presumably when the user generates a command and clicks a button on your GUI you want to see the output from that command before you require the user to enter the next.

这里真正的问题是应用程序是否正在缓冲其输出,以及是否有什么可以阻止它的问题。大概当用户生成命令并单击 GUI 上的按钮时,您希望在要求用户输入下一个命令之前查看该命令的输出。

Unfortunately there's nothing you can do on the client side of subprocess.Popento ensure that when you have passed the application a command the application is making sure that all output is flushed to the final destination. You can call flush()all you like, but if it doesn't do the same, and you can't make it, then you are doomed to looking for workarounds.

不幸的是,您无法在客户端做任何事情subprocess.Popen来确保当您传递应用程序命令时,应用程序确保所有输出都刷新到最终目的地。你可以随心所欲地打电话flush(),但如果它不做同样的事情,而且你做不到,那么你注定要寻找解决方法。

回答by jfs

Your code in the question should work as is. If it doesn't then either your actual code is different (e.g., you might use stdout=PIPEthat may change the child buffering behavior) or it might indicate a bug in the child application itself such as the read-ahead bug in Python 2i.e., your input is sent correctly by the parent process but it is stuck in the child's internal input buffer.

您在问题中的代码应该按原样工作。如果不是,那么要么您的实际代码不同(例如,您可能使用stdout=PIPE它可能会更改子缓冲行为),或者它可能表明子应用程序本身存在错误,例如Python 2 中的预读错误,即您的输入由父进程正确发送,但它卡在子进程的内部输入缓冲区中。

The following works on my Ubuntu machine:

以下适用于我的 Ubuntu 机器:

#!/usr/bin/env python
import time
from subprocess import Popen, PIPE

LINE_BUFFERED = 1

#NOTE: the first argument is a list
p = Popen(['cat'], bufsize=LINE_BUFFERED, stdin=PIPE,
          universal_newlines=True)
with p.stdin:
    for cmd in ["doSomething1\n", "doSomethingElse\n"]:
        time.sleep(1) # a delay to see that the commands appear one by one
        p.stdin.write(cmd)
        p.stdin.flush() # use explicit flush() to workaround
                        #   buffering bugs on some Python versions
rc = p.wait()

回答by Omnifarious

It sounds like your application is treating input from a pipe in a strange way. This means it won't get all of the commands you send until you close the pipe.

听起来您的应用程序正在以一种奇怪的方式处理来自管道的输入。这意味着在您关闭管道之前它不会获得您发送的所有命令。

So the approach I would suggest is just to do this:

所以我建议的方法就是这样做:

process.stdin.write("command1\n")
process.stdin.write("command2\n")
process.stdin.write("command3\n")
process.stdin.close()

It doesn't sound like your Python program is reading output from the application, so it shouldn't matter if you send the commands all at once like that.

听起来您的 Python 程序并不是在读取应用程序的输出,因此如果您像这样一次性发送所有命令,应该没有关系。