如何正确捕获所有 stdout/stderr
how to properly capture all stdout/stderr
并保存到文件中
出于测试目的,我只打印我使用此捕获的内容:
主要包
import (
"bufio"
"bytes"
"fmt"
"io"
"os/exec"
)
func main() {
cmd := exec.Command("/tmp/stdout")
stdout := new(bytes.Buffer)
stderr := new(bytes.Buffer)
cmd.Stdout = stdout
cmd.Stderr = stderr
if err := cmd.Start(); err != nil {
panic(err)
}
if err := cmd.Wait(); err != nil {
panic(err)
}
in := bufio.NewScanner(io.MultiReader(stdout, stderr))
for in.Scan() {
fmt.Println(in.Text())
}
}
可以使用以下代码构建 /tmp/stdout 命令:
package main
import (
"fmt"
"os"
"time"
)
func main() {
for i := 1; i < 1000; i++ {
if i%3 == 0 {
fmt.Fprintf(os.Stderr, "STDERR i: %d\n", i)
} else {
fmt.Printf("STDOUT i: %d\n", i)
}
time.Sleep(1 * time.Second)
}
}
出于某种原因,我无法从输出中捕获任何内容,如果我 运行 /tmp/stdout
命令我得到这个:
$ /tmp/stdout
STDOUT i: 1
STDOUT i: 2
STDERR i: 3
STDOUT i: 4
STDOUT i: 5
STDERR i: 6
STDOUT i: 7
我期望在使用之前的代码从 go 调用它时可以获得相同的输出,奇怪的是,如果我将命令更改为 id
、whoami
uname
我确实得到了结果并且可以打印,因此想知道哪里出了问题。
有什么想法吗?
更新
发现我必须等待程序完成,如评论中所建议的那样才能获得输出,但如果我想实时获得输出,我该如何实现,可能是什么最好的方法,io.Copy
和 os.Pipe
等 ?
but in case I would like to get the output in realtime
一种方法是将 os.Stdout
附加到 cmd.Stdout
oCmd := exec.Command(bin, cmdArgs...)
oCmd.Stdout = os.Stdout
oCmd.Stderr = os.Stderr
err := oCmd.Run()
然后您可以使用文件代替 f,_ := os.Create("file")
。
如果你想同时将它写入文件和终端,我怀疑(我还没有这样做),你需要使用 io.Mutiwriters
f, _ := os.Create("file")
cmd.Stdout = io.MultiWriter(os.Stdout, f)
出于测试目的,我只打印我使用此捕获的内容:
主要包
import (
"bufio"
"bytes"
"fmt"
"io"
"os/exec"
)
func main() {
cmd := exec.Command("/tmp/stdout")
stdout := new(bytes.Buffer)
stderr := new(bytes.Buffer)
cmd.Stdout = stdout
cmd.Stderr = stderr
if err := cmd.Start(); err != nil {
panic(err)
}
if err := cmd.Wait(); err != nil {
panic(err)
}
in := bufio.NewScanner(io.MultiReader(stdout, stderr))
for in.Scan() {
fmt.Println(in.Text())
}
}
可以使用以下代码构建 /tmp/stdout 命令:
package main
import (
"fmt"
"os"
"time"
)
func main() {
for i := 1; i < 1000; i++ {
if i%3 == 0 {
fmt.Fprintf(os.Stderr, "STDERR i: %d\n", i)
} else {
fmt.Printf("STDOUT i: %d\n", i)
}
time.Sleep(1 * time.Second)
}
}
出于某种原因,我无法从输出中捕获任何内容,如果我 运行 /tmp/stdout
命令我得到这个:
$ /tmp/stdout
STDOUT i: 1
STDOUT i: 2
STDERR i: 3
STDOUT i: 4
STDOUT i: 5
STDERR i: 6
STDOUT i: 7
我期望在使用之前的代码从 go 调用它时可以获得相同的输出,奇怪的是,如果我将命令更改为 id
、whoami
uname
我确实得到了结果并且可以打印,因此想知道哪里出了问题。
有什么想法吗?
更新
发现我必须等待程序完成,如评论中所建议的那样才能获得输出,但如果我想实时获得输出,我该如何实现,可能是什么最好的方法,io.Copy
和 os.Pipe
等 ?
but in case I would like to get the output in realtime
一种方法是将 os.Stdout
附加到 cmd.Stdout
oCmd := exec.Command(bin, cmdArgs...)
oCmd.Stdout = os.Stdout
oCmd.Stderr = os.Stderr
err := oCmd.Run()
然后您可以使用文件代替 f,_ := os.Create("file")
。
如果你想同时将它写入文件和终端,我怀疑(我还没有这样做),你需要使用 io.Mutiwriters
f, _ := os.Create("file")
cmd.Stdout = io.MultiWriter(os.Stdout, f)