Spawn子进程需要控制台输入而不阻塞?

时间:2021-02-27 20:27:16

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

2 个解决方案

#1


  • Remove the shell=True part. Your shell has nothing to do with it. Using shell=True is a common cause of trouble.
  • 删除shell = True部分。你的shell与它无关。使用shell = True是导致问题的常见原因。

  • Use a list of parameters for cmd.
  • 使用cmd的参数列表。

Example:

cmd = ['cvs', 
       '-d:pserver:anonymous@bayonne.cvs.sourceforge.net:/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't just write the password to the subprocess' stdin.

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

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。

#2


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

如果你要自动化需要输入的外部程序 - 比如密码 - 你最好的选择可能是使用pexpect。

#1


  • Remove the shell=True part. Your shell has nothing to do with it. Using shell=True is a common cause of trouble.
  • 删除shell = True部分。你的shell与它无关。使用shell = True是导致问题的常见原因。

  • Use a list of parameters for cmd.
  • 使用cmd的参数列表。

Example:

cmd = ['cvs', 
       '-d:pserver:anonymous@bayonne.cvs.sourceforge.net:/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't just write the password to the subprocess' stdin.

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

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。

#2


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

如果你要自动化需要输入的外部程序 - 比如密码 - 你最好的选择可能是使用pexpect。