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

下面的代码完全符合我的要求,只将其打印到控制台。

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

cmd.Stdout = os.Stdout

cmd.Stderr = os.Stderr

if err := cmd.Run(); err != nil {

log.Fatal(err)

}

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

}

输出:

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

我想要实现的是:

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

我试过将stdout和stderr命令传递到扫描仪中或使用io.Copy,它们分别在goroutine中进行,但是未维护输出顺序。可能是因为goroutine之间的交替必须在输出交替的同时发生,这几乎是不可能的。

我也尝试过使用“中选择”作为从例子在这里。但是没有保持输出顺序。

Logstreamer也存在同样的问题。

我必须尝试的另一个想法是看看是否可以从控制台缓冲区中读取内容,但这感觉不对。

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

回答:

正如我在评论部分中所述,可以使用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)

}

}

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

以上是 在实时输出时,如何将命令的stdout和stderr重定向到控制台和日志文件? 的全部内容, 来源链接: utcz.com/qa/406809.html

回到顶部