重定向Go中子进程的stdout管道
Posted
技术标签:
【中文标题】重定向Go中子进程的stdout管道【英文标题】:Redirect stdout pipe of child process in Go 【发布时间】:2012-02-11 02:25:02 【问题描述】:我正在用 Go 编写一个程序,它执行类似服务器的程序(也是 Go)。现在我想在我启动父程序的终端窗口中拥有子程序的标准输出。一种方法是使用cmd.Output()
函数,但这仅在进程退出后打印标准输出。 (这是一个问题,因为这个类似服务器的程序运行了很长时间,我想读取日志输出)
变量out
属于type io.ReadCloser
,我不知道应该用它做什么来完成我的任务,而且我在网上找不到关于这个主题的任何有用信息。
func main()
cmd := exec.Command("/path/to/my/child/program")
out, err := cmd.StdoutPipe()
if err != nil
fmt.Println(err)
err = cmd.Start()
if err != nil
fmt.Println(err)
//fmt.Println(out)
cmd.Wait()
代码说明:取消注释Println
函数以获得要编译的代码,我知道Println(out io.ReadCloser)
不是一个有意义的函数。
(它产生输出 &3 |0 <nil> 0
)这两行只是让代码编译所必需的。
【问题讨论】:
导入语句的“exec”行应该是“os/exec”。 感谢您的信息,实际上它只是 exec pre go1,现在它在 os 中。为 go1 更新了它 我认为您实际上不需要在 go 例程中调用io.Copy
我认为您不需要调用cmd.Wait()
或for
循环......为什么这些在这里?
@weberc2 看不起 elimisteve 的回答。如果您只想运行程序一次,则不需要 for 循环。但是如果你不调用 cmd.Wait(),你的 main() 可能会在你调用的程序完成之前结束,并且你不会得到你想要的输出
【参考方案1】:
我相信如果你导入 io
和 os
并替换这个:
//fmt.Println(out)
用这个:
go io.Copy(os.Stdout, out)
(参见文档for io.Copy
和for os.Stdout
),它会做你想做的事。 (免责声明:未经测试。)
顺便说一句,您可能还想使用与标准输出相同的方法来捕获标准错误,但使用cmd.StderrPipe
和os.Stderr
。
【讨论】:
@mbert:我已经使用了足够多的其他语言,并且已经阅读了足够多的关于 Go 的知识,因此预感可能存在哪些功能来执行此操作,以及大概以什么形式存在;然后我只需要查看相关的包文档(由谷歌搜索找到)以确认我的预感是正确的,并找到必要的细节。最难的部分是 (1) 找到调用的标准输出 (os.Stdout
) 和 (2) 确认前提,如果您根本不调用 cmd.StdoutPipe()
,标准输出将转到 /dev/null
而不是而不是父进程的标准输出。【参考方案2】:
对于那些在循环中不需要它,但希望命令输出回显到终端而不让cmd.Wait()
阻塞其他语句的人:
package main
import (
"fmt"
"io"
"log"
"os"
"os/exec"
)
func checkError(err error)
if err != nil
log.Fatalf("Error: %s", err)
func main()
// Replace `ls` (and its arguments) with something more interesting
cmd := exec.Command("ls", "-l")
// Create stdout, stderr streams of type io.Reader
stdout, err := cmd.StdoutPipe()
checkError(err)
stderr, err := cmd.StderrPipe()
checkError(err)
// Start command
err = cmd.Start()
checkError(err)
// Don't let main() exit before our command has finished running
defer cmd.Wait() // Doesn't block
// Non-blockingly echo command output to terminal
go io.Copy(os.Stdout, stdout)
go io.Copy(os.Stderr, stderr)
// I love Go's trivial concurrency :-D
fmt.Printf("Do other stuff here! No need to wait.\n\n")
【讨论】:
Minor fyi:(显然)如果你的“在这里做其他事情”比 goroutines 完成得更快,你可能会错过 goroutines 启动的结果。 main() 退出也会导致 goroutines 结束。因此,如果您不等待 cmd 完成,则可能最终不会实际输出以在终端中回显。【参考方案3】:现在我想在我的终端中拥有子程序的标准输出 我启动父程序的窗口。
无需使用管道或 goroutine,这很简单。
func main()
// Replace `ls` (and its arguments) with something more interesting
cmd := exec.Command("ls", "-l")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Run()
【讨论】:
此外,如果您希望该命令侦听输入,您可以简单地设置cmd.Stdin = os.Stdin
,从而使其就好像您已经从您的 shell 中执行了该命令。
对于那些希望重定向到log
而不是标准输出的人,有一个答案here以上是关于重定向Go中子进程的stdout管道的主要内容,如果未能解决你的问题,请参考以下文章