windows 生成期望控制台输入而不阻塞的子进程?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/510751/
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-09-15 11:55:46  来源:igfitidea点击:

Spawn subprocess that expects console input without blocking?

pythonwindowssubprocess

提问by rpg

I am trying to do a CVS login from Python by calling the cvs.exe process. When calling cvs.exe by hand, it prints a message to the console and then waits for the user to input the password.

我正在尝试通过调用 cvs.exe 进程从 Python 进行 CVS 登录。当手动调用 cvs.exe 时,它​​会向控制台打印一条消息,然后等待用户输入密码。

When calling it with subprocess.Popen, I've noticed that the call blocks. The code is

当用 subprocess.Popen 调用它时,我注意到调用块。代码是

subprocess.Popen(cvscmd, shell = True, stdin = subprocess.PIPE, stdout = subprocess.PIPE,
    stderr = subprocess.PIPE)

I assume that it blocks because it's waiting for input, but my expectation was that calling Popen would return immediately and then I could call subprocess.communicate() to input the actual password. How can I achieve this behaviour and avoid blocking on Popen?

我假设它阻塞是因为它在等待输入,但我的期望是调用 Popen 会立即返回,然后我可以调用 subprocess.communicate() 来输入实际密码。我怎样才能实现这种行为并避免在 Popen 上阻塞?

OS: Windows XP
Python: 2.6
cvs.exe: 1.11

操作系统:Windows XP
Python:2.6
cvs.exe:1.11

采纳答案by nosklo

  • Remove the shell=Truepart. Your shell has nothing to do with it. Using shell=Trueis a common cause of trouble.
  • Use a list of parameters for cmd.
  • 取下shell=True零件。你的外壳与它无关。使用shell=True是造成问题的常见原因。
  • 使用 cmd 的参数列表。

Example:

例子:

cmd = ['cvs', 
       '-d:pserver:[email protected]:/cvsroot/bayonne', 
       'login']
p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE) 

This won't block on my system (my script continues executing). However since cvs reads the password directly from the terminal (not from standard input or output) you can'tjust write the password to the subprocess' stdin.

这不会在我的系统上阻塞(我的脚本继续执行)。然而,由于 cvs 直接从终端(而不是从标准输入或输出)读取密码,您不能只将密码写入子进程的标准输入。

What you could do is pass the password as part of the CVSROOT specification instead, like this:

您可以做的是将密码作为 CVSROOT 规范的一部分传递,如下所示:

:pserver:<user>[:<passwd>]@<server>:/<path>

I.e. a function to login to a sourceforge project:

即登录 sourceforge 项目的函数:

import subprocess

def login_to_sourceforge_cvs(project, username='anonymous', password=''):
    host = '%s.cvs.sourceforge.net' % project
    path = '/cvsroot/%s' % project
    cmd = ['cvs', 
           '-d:pserver:%s:%s@%s:%s' % (username, password, host, path), 
           'login']
    p = subprocess.Popen(cmd, stdin=subprocess.PIPE, 
                              stdout=subprocess.PIPE
                              stderr=subprocess.STDOUT) 
    return p

This works for me. Calling

这对我有用。打电话

login_to_sourceforge_cvs('bayonne')

Will log in anonymously to the bayonne project's cvs.

会匿名登录bayonne项目的cvs。

回答by Heikki Toivonen

If you are automating external programs that need input - like password - your best bet would probably be to use pexpect.

如果您正在自动化需要输入(例如密码)的外部程序,那么最好的选择可能是使用pexpect