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

I can't see the output of a subprocess in Python

我正在制作一个与 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()

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

感谢您的提问

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

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.

您看不到输出,因为您已经重定向了子进程的两个 stdout/stderr。

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

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

修复它:一次读取一个字符而不是逐行读取,运行 python 使用 -u 选项(或使用 PYTHONUNBUFFERED envvar)来禁用缓冲。

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

#!/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