【问题标题】:Write stdout stream to file将标准输出流写入文件
【发布时间】:2018-02-22 12:05:31
【问题描述】:

我正在通过exec.Command() 运行一个外部进程,我希望将命令中的标准输出实时打印并写入文件(类似于在命令行中使用tee)。

我可以通过扫描仪和写入器实现这一点:

cmd := exec.Command("mycmd")
cmdStdOut, _ := cmd.StdoutPipe()

s := bufio.NewScanner(cmdStdOut)
f, _ := os.Create("stdout.log")
w := bufio.NewWriter(f)

go func() {
    for s.Scan(){
        t := s.Text()
        fmt.Println(t)
        fmt.Fprint(w, t)
        w.Flush()    
    }
}

有没有更惯用的方法来避免破坏ScanFlush

【问题讨论】:

  • cmd.Stdout = f
  • 哦.....谢谢!
  • 但不要忘记处理错误...
  • 是的,为了简洁起见,我忽略了 stderr / 错误。我现在还想知道我想在编写它的同时使用 stdout 流(例如,像 tee)。也许我会更新这个问题。
  • io.MultiWriter 加 io.Pipe

标签: file go stream stdout


【解决方案1】:

为命令的标准输出分配一个多写入器,用于写入文件和管道。然后,您可以使用管道的读取端来跟踪输出。

此示例的行为类似于tee 工具:

package main

import (
    "io"
    "os"
    "os/exec"
)

func main() {
    var f *os.File // e.g. os.Create, os.Open

    r, w := io.Pipe()
    defer w.Close()

    cmd := exec.Command("mycmd")
    cmd.Stdout = io.MultiWriter(w, f)

    // do something with the output while cmd is running by reading from r
    go io.Copy(os.Stdout, r) 

    cmd.Run()
}

StdoutPipe 的替代方案:

package main

import (
    "io"
    "os"
    "os/exec"
)

func main() {
    var f *os.File

    cmd := exec.Command("date")
    stdout, _ := cmd.StdoutPipe()

    go io.Copy(io.MultiWriter(f, os.Stdout), stdout)

    cmd.Run()
}

【讨论】:

  • 感谢其他示例!
【解决方案2】:

为简洁起见忽略错误。正如其他答案所述,您可以在 io.Copy 中使用 io.MultiWriter,但是当您处理 stdout exec.Cmd,您需要注意 Wait 在命令终止后立即关闭管道,如文档 (https://golang.org/pkg/os/exec/#Cmd.StdoutPipe) 所述。

Wait 会在看到命令退出后关闭管道,所以大多数调用者不需要自己关闭管道。因此,在管道的所有读取完成之前调用 Wait 是不正确的。

忽略这一点可能会导致输出的某些部分未被读取,因此会丢失。相反,不要使用 Run,而是使用 StartWait。例如。

package main

import (
    "io"
    "os"
    "os/exec"
)

func main() {
    cmd := exec.Command("date")
    stdout, _ := cmd.StdoutPipe()
    f, _ := os.Create("stdout.log")

    cmd.Start()
    io.Copy(io.MultiWriter(f, os.Stdout), stdout)
    cmd.Wait()
}

这将确保从 stdout 读取所有内容并随后关闭所有管道。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-06-01
    • 2013-03-18
    • 2018-12-07
    • 2011-04-09
    • 1970-01-01
    • 2017-06-03
    • 2019-03-16
    • 1970-01-01
    相关资源
    最近更新 更多