简体   繁体   English

打印子进程的标准输出 pipe 忽略最后几行

[英]printing stdout pipe of sub processes ignore last lines

I'm trying to run a sub processes and watching his stdout until I find desirable string.我正在尝试运行一个子进程并观察他的标准输出,直到找到所需的字符串。 this is my code:这是我的代码:

    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!")

the issue here is that for some reason the function waitForAppOutput stop printing stdout few lines before the "done."这里的问题是,由于某种原因,function waitForAppOutput在“完成”之前停止打印标准输出几行。 which is the last line that should appear in the stdout .这是应该出现在 stdout 中的最后一行。 I assume iter(proc.stdout.readline, b'') is blocking and readline is not able to read the last lines of the stdout.我假设iter(proc.stdout.readline, b'')被阻塞并且readline无法读取标准输出的最后几行。

any idea what is the issue here?知道这里有什么问题吗?

You have a misspelling: it should be waitForAppOutput instead of waitForAppOutout .你有一个拼写错误:它应该是waitForAppOutput而不是waitForAppOutout How does this even run at all?这甚至是如何运行的? And when you are invoking a command using a shell, you should not be passing an array of strings but rather one single string.当您使用 shell 调用命令时,您不应该传递字符串数组,而是传递一个字符串。

Normally one should use the communicate method on the return subprocess object from the Popen call to prevent potential deadlocks (which seems to be what you are experiencing).通常应该在Popen调用的返回子进程 object 上使用communicate方法来防止潜在的死锁(这似乎是您正在经历的)。 This returns a tuple: (stdout, stderr) , the stdout and stderr output strings:这将返回一个元组: (stdout, stderr)stdoutstderr output 字符串:

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!")

The only issue is if the output strings are large (whatever your definition of large might be), for it might be memory-inefficient or even prohibitive to read the entire output into memory.唯一的问题是 output 字符串是否很大(无论您对的定义可能是什么),因为将整个 output 读取到 ZCD69B4957F06CDE218D7BF3D61980 中可能会导致内存效率低下甚至令人望而却步。 If this is your situation, then I would try to avoid the deadlock by piping only stdout .如果这是您的情况,那么我会尝试通过仅管道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

Update更新

Here is an example using both techniques that runs the Windows sort command to sort a bunch of input lines.这是一个使用这两种技术的示例,该技术运行 Windows sort命令来对一堆输入行进行排序。 This works particularly well both ways because the sort command does not start output until all the input has been read, so it's a very simple protocol in which deadlocking is easy to avoid.这两种方式都特别有效,因为排序命令在读取所有输入之前不会启动 output,因此它是一个非常简单的协议,其中很容易避免死锁。 Try running this with USE_COMMUNICATE set alternately to True and False :尝试在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

Prints:印刷:

e
i
o
p
q
r
t
u
w
y

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM