如何在实时输出时将命令的stdout和stderr重定向到控制台和日志文件?

use*_*900 4 io synchronization go

下面的代码完全符合我的要求,除了它只打印到控制台.

cmd := exec.Command("php", "randomcommand.php")

cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr

if err := cmd.Run(); err != nil {
    log.Fatal(err)
}
Run Code Online (Sandbox Code Playgroud)

randomcommand.php:

// randomcommand.php simply alternates output between stdout and stderr 20 times

$stdout = fopen('php://stdout', 'w+');
$stderr = fopen('php://stderr', 'w+');
for ($i = 1;$i <= 20; $i++) {
    fwrite($stdout, "stdout $i\n");
    fwrite($stderr, "stderr $i\n");
}
Run Code Online (Sandbox Code Playgroud)

输出:

stdout 1
stderr 1
stdout 2
stderr 2
stdout 3
stderr 3
stdout 4
stderr 4
stdout 5
stderr 5
stdout 6
stderr 6
stdout 7
stderr 7
stdout 8
stderr 8
stdout 9
stderr 9
stdout 10
stderr 10
stdout 11
stderr 11
stdout 12
stderr 12
stdout 13
stderr 13
stdout 14
stderr 14
stdout 15
stderr 15
stdout 16
stderr 16
stdout 17
stderr 17
stdout 18
stderr 18
stdout 19
stderr 19
stdout 20
stderr 20
Run Code Online (Sandbox Code Playgroud)

我想要实现的是:

  1. 将命令的stdout和stderr实时打印到控制台;
  2. 将命令的stdout和stderr记录到文件中,与控制台中显示的完全相同;
  3. 尊重写入stdout和stderr的确切顺序,并且;
  4. 不要修改命令本身

我已经尝试将命令stdout和stderr连接到扫描仪或使用io.Copy,每个都在goroutine中,但是输出的顺序没有被维护.可能因为goroutines之间的交替必须在输出交替的同时发生,这几乎是不可能的.

我也尝试过使用"select",就像这里的例子一样.但是没有保持产出的顺序.

Logstreamer也有同样的问题.

我必须尝试的另一个想法是看看我是否能以某种方式从控制台缓冲区中读取,但这感觉不对.

有谁知道这是否可能,值得追求?

Dep*_*ado 12

正如我在评论部分所说,这可以使用MultiWriter实现

package main

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

func main() {
    // Logging capability
    f, err := os.OpenFile("log.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
    if err != nil {
        log.Fatalf("Error opening file: %v", err)
    }
    defer f.Close()
    mwriter := io.MultiWriter(f, os.Stdout)
    cmd := exec.Command("ls")
    cmd.Stderr = mwriter
    cmd.Stdout = mwriter
    err = cmd.Run() //blocks until sub process is complete
    if err != nil {
        panic(err)
    }
}
Run Code Online (Sandbox Code Playgroud)

声明命令时,在运行命令之前,只需指定Stdout和Stderr正在使用上面定义的MultiWriter.此MultiWriter实例包含日志文件和标准输出.

  • 德帕多,你是个疯子!答案很简单,我无法在我面前看到它。谢谢! (2认同)