生成子进程并等待控制台输入而不阻塞?

4

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

但是,当使用subprocess.Popen调用它时,我注意到该调用会阻塞。以下是代码:

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

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

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

2个回答

2
  • 删除shell=True部分。你的shell与此无关。使用shell=True是问题的常见原因。
  • 为cmd使用参数列表。

示例:

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

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

你可以将密码作为CVSROOT规范的一部分传递,像这样:

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

例如,登录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

这对我有效。调用:

login_to_sourceforge_cvs('bayonne')

将匿名登录Bayonne项目的CVS。

将密码作为CVSROOT的一部分似乎是一个更好的主意,但是传递密码会让cvs.exe认为用户名实际上是"user:password"!例如,在命令行中键入"cvs-d:pserver:user:pass@server:path"尝试登录"user:pass",它仍然要求输入密码。 - rpg
@Razvan:我的CVS版本似乎像我说的那样工作。也许你有修改过的版本?你从哪里获取你的cvs?你可以升级吗?你试过我的示例代码了吗? - nosklo
nosklo,我尝试删除shell=True并将命令行传递为列表,但由于cvs.exe的行为,这并没有起作用。 我采取了您的建议,并从ftp.gnu.org重新下载了cvs.exe,因为我拥有的二进制文件是从另一个站点下载的。它起作用了!感谢您的帮助。 - rpg

0

如果你需要自动化外部程序并且需要输入,比如密码,你最好使用 pexpect


但是你不能在Windows系统上使用pexpect。是的,有一个叫做wexpect的端口,但我无法让它工作。看起来它仍在开发中。 - Roman Hwang

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接