打印子进程的标准管道忽略最后一行

2024-10-04 03:15:48 发布

您现在位置:Python中文网/ 问答频道 /正文

我试着运行一个子进程并观察他的标准输出,直到找到所需的字符串。 这是我的代码:

    def waitForAppOutput(proc, word):
        for stdout_line in iter(proc.stdout.readline, b''):
           print stdout_line
           if word in stdout_line.rstrip():
              return;

    p = Popen(["./app.sh"], shell=True, stdin=PIPE ,stdout=PIPE, stderr=PIPE)
    waitForAppOutput(p,"done!")

这里的问题是,出于某种原因,函数waitForAppOutput在“done!”之前的几行停止打印标准输出,这是应该出现在标准输出中的最后一行。我假设iter(proc.stdout.readline, b'')正在阻塞,并且readline无法读取标准输出的最后几行

你知道这里有什么问题吗


Tags: 字符串代码in标准readline进程defstdout
1条回答
网友
1楼 · 发布于 2024-10-04 03:15:48

您有一个拼写错误:它应该是waitForAppOutput,而不是waitForAppOutout。这到底是怎么回事?当您使用shell调用命令时,不应传递字符串数组,而应传递单个字符串

通常,应该对来自Popen调用的返回子流程对象使用communicate方法来防止潜在的死锁(这似乎是您正在经历的)。这将返回一个元组:(stdout, stderr)stdoutstderr输出字符串:

from subprocess import Popen, PIPE


def waitForAppOutput(stdout_lines, word):
    for stdout_line in stdout_lines:
       print stdout_line
       if word in stdout_line.rstrip():
          return;

p = Popen("./app.sh", shell=True, stdout=PIPE, stderr=PIPE, stdin=PIPE, universal_newlines=True)
expected_input = "command line 1\ncommand line 2\n"
stdout, stderr = p.communicate(expected_input)
stdout_lines = stdout.splitlines()
waitForAppOutput(stdout_lines, "done!")

唯一的问题是,如果输出字符串很大(无论您对large的定义是什么),因为将整个输出读入内存可能会导致内存效率低下甚至禁止。如果这是您的情况,那么我将尝试通过只使用管道stdout来避免死锁

from subprocess import Popen, PIPE


def waitForAppOutput(proc, word):
    for stdout_line in iter(proc.stdout.readline, ''):
       print stdout_line
       if word in stdout_line.rstrip():
          return;

p = Popen("./app.sh", shell=True, stdout=PIPE, stdin=PIPE, universal_newlines=True)
expected_input = "command line 1\ncommand line 2\n"
p.stdin.write(expected_input)
p.stdin.close()
waitForAppOutput(p, "done!")
for stdout_line in iter(p.stdout.readline, ''):
    pass # read rest of output
p.wait() # wait for termination

更新

下面是一个使用这两种技术的示例,它运行Windows sort命令对一组输入行进行排序。这两种方式都非常有效,因为sort命令在读取所有输入之前不会启动输出,因此它是一个非常简单的协议,死锁很容易避免。尝试在USE_COMMUNICATE交替设置为TrueFalse的情况下运行此命令:

from subprocess import Popen, PIPE

USE_COMMUNICATE = False

p = Popen("sort", shell=True, stdout=PIPE, stdin=PIPE, universal_newlines=True)
expected_input = """q
w
e
r
t
y
u
i
o
p
"""
if USE_COMMUNICATE:
    stdout_lines, stderr_lines = p.communicate(expected_input)
    output = stdout_lines
else:
    p.stdin.write(expected_input)
    p.stdin.close()
    output = iter(p.stdout.readline, '')
for stdout_line in output:
    print stdout_line,
p.wait() # wait for termination

印刷品:

e
i
o
p
q
r
t
u
w
y

相关问题 更多 >