【问题标题】:Spawn subprocess that expects console input without blocking?产生期望控制台输入而不阻塞的子进程?
【发布时间】:2010-10-05 09:00:38
【问题描述】:

我正在尝试通过调用 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

【问题讨论】:

    标签: python windows subprocess


    【解决方案1】:

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

    【讨论】:

    • 但是你不能在 Windows 系统上使用 pexpect。是的,有一个名为 wexpect 的端口,但我无法让它工作。好像还在开发中。
    【解决方案2】:
    • 删除shell=True 部分。你的外壳与它无关。使用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 直接从终端读取密码(而不是从标准输入或输出),您不能只将密码写入子进程的标准输入。

    您可以做的是将密码作为 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项目的简历。

    【讨论】:

    • 密码作为 CVSROOT 的一部分似乎是一个更好的主意,但是传递密码会使 cvs.exe 认为用户名实际上是“user:password”!例如:在命令行输入 cvs -d :pserver:user:pass@server:path 尝试登录“user:pass”,但它仍然要求输入密码
    • @Razvan:我的 CVS 版本似乎可以正常工作。也许你有修改版?你从哪里得到你的简历?可以升级吗?你试过我的示例代码吗?
    • nosklo,我尝试删除 shell=True 并将命令行作为列表传递,但由于 cvs.exe 行为,这不起作用。我听取了您的建议并从 ftp.gnu.org 重新下载了 cvs.exe,因为我的二进制文件是从另一个站点下载的。有效!感谢您的帮助。
    猜你喜欢
    • 2011-01-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多