我无法在Python中看到子进程的输出

时间:2015-04-11 14:22:56

标签: python subprocess

我正在创建一个与Sphinx-Quickstart交互的程序。所以我想要做的是我的程序识别单词“path”然后输入一个特定的值。与其他人一样的情况,当我没有特定的单词时,只需输入一个输入('\ n')。我这样做是因为Sphinx有时会改变问题的顺序,如果我使用沟通,他们就会失败。

我想到这样的事情:

 import subprocess
 from subprocess import PIPE
p = subprocess.Popen('sphinx-quickstart', stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=PIPE, shell=True, bufsize=0)
p.stdin.write('doc\n')
a=p.stdout.readline()
print a.read()
while out:
   line = out
   line = line.rstrip("\n")

   if "autodoc" in line:
    pr = 1
    p.stdin.write('y\n')
    out = p.stdout.readline()
    continue

   if "source and build" in line:
    pr = 2
    p.stdin.write('y\n')
    out = p.stdout.readline()
    continue

out = p.stdout.readline()
p.stdin.close()
p.wait()

当我尝试读取输出时,我的程序挂起。

感谢您的提问

2 个答案:

答案 0 :(得分:1)

您没有看到输出,因为您已重定向子流程的两个stdout / stderr。

您的程序挂起,因为sphinx-quickstart等待您提供一些输入,例如,传递换行符以接受默认值,或者如果没有默认值则输入内容,例如,对于项目名称,作者值。

另一个原因是:之后没有新行,sphinx-quickstart在重定向stdout时不会及时刷新提示。

要解决此问题:一次读取一个字符而不是逐行读取,并使用python选项运行-u(或使用PYTHONUNBUFFERED envvar)禁用缓冲。

每次在输出中看到提示行(以':' char结尾)时,请确保脚本提供有效输入:

#!/usr/bin/env python
from __future__ import print_function
import os
from subprocess import Popen, PIPE, CalledProcessError

answers = {
    'Root path': 'doc',
    'source and build': 'y',
    'autodoc': 'y',
    'Project name': '<Project name>',
    'Author name': '<author>',
    'Project version': '<version>',
}

def iter_chunks(pipe, terminator_char):
    """Yield chunks from *pipe* that end with *terminator_char*."""
    buf = []
    for char in iter(lambda: pipe.read(1), ''):
        buf.append(char)
        if char == terminator_char:
            yield ''.join(buf)
            del buf[:]
    if buf: # last chunk
        yield ''.join(buf)

cmd = ['sphinx-quickstart']
p = Popen(cmd, stdin=PIPE, stdout=PIPE, universal_newlines=True, bufsize=0,
          env=dict(os.environ, PYTHONUNBUFFERED='1'))
with p.stdin, p.stdout: # close pipes at the end
    for chunk in iter_chunks(p.stdout, ':'):
        line = chunk.rpartition('\n')[-1] # get last line
        if line.lstrip().startswith('>') and line.endswith(':'): # found prompt
            answer = next((a for q, a in answers.items() if q in line), '')
            print(answer, file=p.stdin) #NOTE: short write is possible
if p.wait() != 0: # raise on non-zero exit status
    raise CalledProcessError(p.returncode, cmd)

注意:stderr未重定向

您还可以使用pexpect模块与外部命令example进行类似对话的交互。

答案 1 :(得分:0)

不确定你想要什么,但这将运行并寻找正确的子串:

from subprocess import PIPE,Popen,STDOUT

p = Popen('sphinx-quickstart', stdout=PIPE, stderr=STDOUT, stdin=PIPE, universal_newlines=True)
p.stdin.write('doc\n')
for line in iter(p.stdout.readline, ""):
    print(line.rstrip())
    if "autodoc" in line:
        pr = 1
        p.stdin.write('y\n')
    elif '"source" and "build"' in line:
        pr = 2
        p.stdin.write('y\n')

当你运行代码时,你会看到输出,源代码和构建都用引号括起来,所以你的if永远不会起作用。

for line in iter(p.stdout.readline, "")会实时读取输出,取代你的while循环。

输出:

Welcome to the Sphinx 1.2.2 quickstart utility.

Please enter values for the following settings (just press Enter to
accept a default value, if one is given in brackets).

Enter the root path for documentation.
> Root path for the documentation [.]:
You have two options for placing the build directory for Sphinx output.
Either, you use a directory "_build" within the root path, or you separate
"source" and "build" directories within the root path.
> Separate source and build directories (y/n) [n]:
Inside the root directory, two more directories will be created; "_templates"
for custom HTML templates and "_static" for custom stylesheets and other static
files. You can enter another prefix (such as ".") to replace the underscore.