简体   繁体   English

从“ exec.Cmd”中实时获取输出

[英]Getting output from `exec.Cmd` in “real-time”

This question is similar to Golang - Copy Exec output to Log except it is concerned with the buffering of output from exec commands. 这个问题类似于Golang-将Exec输出复制到Log,除了它与exec命令的输出缓冲有关。

I have the following test program: 我有以下测试程序:

package main

import (
    "fmt"
    "log"
    "os/exec"
)

func main() {
    cmd := exec.Command("python", "inf_loop.py")
    var out outstream
    cmd.Stdout = out
    if err := cmd.Start(); err != nil {
        log.Fatal(err)
    }
    fmt.Println(cmd.Wait())
}

type outstream struct{}

func (out outstream) Write(p []byte) (int, error) {
    fmt.Println(string(p))
    return len(p), nil
}

inf_loop.py , which the above refers to, simply contains: 上面提到的inf_loop.py仅包含:

print "hello"
while True:
    pass

The go program hangs when I run it and doesn't output anything, but if I use os.Stdout instead of out then it outputs "hello" before it hangs. 当我运行go程序时,它会挂起并且不输出任何内容,但是如果我使用os.Stdout而不是out那么它将在挂起之前输出“ hello”。 Why is there a discrepancy between the two io.Writer s and how can it be fixed? 为什么两个io.Writer之间存在差异,并且如何解决?

Some more diagnostic information: 一些更多的诊断信息:

  • When the loop is removed from inf_loop.py then "hello" is output from both programs, as expected. inf_loop.py删除循环后,两个程序将按预期输出“ hello”。
  • When using yes as the program instead of the python script and outputting len(p) in outstream.Write then there is output, and the output is usually 16384 or 32768. This indicates to me that this is a buffering issue, as I originally anticipated, but I still don't understand why the outstream structure is being blocked by buffering but os.Stdout isn't. 当使用yes作为程序而不是python脚本并在outstream.Write输出len(p) ,将输出,输出通常为16384或32768。这向我表明这是一个缓冲问题,正如我最初预期的那样,但我还是不明白为什么outstream结构被阻止通过缓冲,但os.Stdout不是。 One possibility is that the behaviour is the result of the way that exec passes the io.Writer directly to os.StartProcess if it is an os.File (see source for details), otherwise it creates an os.Pipe() between the process and the io.Writer , and this pipe may be causing the buffering. 一种可能性是,该行为是该方法的结果exec传递io.Writer直接os.StartProcess如果它是一个os.File (见的详细信息),否则它创建一个os.Pipe()的处理之间和io.Writer ,并且此管道可能正在引起缓冲。 However, the operation and possible buffering of os.Pipe() is too low-level for me to investigate. 但是, os.Pipe()的操作和可能的缓冲级别太低,我无法研究。

Python buffers stdout by default. Python默认情况下会缓冲stdout。 Try this program: 试试这个程序:

import sys
print "hello"
sys.stdout.flush()
while True:
    pass

or run Python with unbuffered stdout and stderr: 或使用无缓冲的stdout和stderr运行Python:

cmd := exec.Command("python", "-u", "foo.py")

Note the -u flag. 注意-u标志。

You see different results when using cmd.Stout = os.Stdout because Python uses line buffering when stdout is a terminal. 使用cmd.Stout = os.Stdout时会看到不同的结果,因为当stdout为终端时,Python使用行缓冲。

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

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