在Go中重定向子进程的标准输出管道。

huangapple go评论87阅读模式
英文:

Redirect stdout pipe of child process in Go

问题

我正在使用Go编写一个执行类似服务器程序的程序(也是Go语言)。现在我想要在启动父程序的终端窗口中获取子程序的标准输出(stdout)。一种方法是使用cmd.Output()函数,但是这个函数只会在进程退出后才打印stdout。(这是个问题,因为这个类似服务器的程序运行时间很长,我想要读取日志输出)

变量out的类型是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})这两行只是为了让代码能够编译通过。

英文:

I'm writing a program in Go that executes a server like program (also Go). Now I want to have the stdout of the child program in my terminal window where I started the parent program. One way to do this is with the cmd.Output() function, but this prints the stdout only after the process has exited. (That's a problem because this server-like program runs for a long time and I want to read the log output)

The variable out is of type io.ReadCloser and I don't know what I should do with it to achieve my task, and I can't find anything helpful on the web on this topic.

func main() {
	cmd := exec.Command(&quot;/path/to/my/child/program&quot;)
	out, err := cmd.StdoutPipe()
	if err != nil {
	    fmt.Println(err)
	}
	err = cmd.Start()
	if err != nil {
		fmt.Println(err)
	}
    //fmt.Println(out)
	cmd.Wait()
} 

Explanation to the code: uncomment the Println function to get the code to compile, I know that Println(out io.ReadCloser) is not a meaningful function.
(it produces the output &amp;{3 |0 &lt;nil&gt; 0} ) These two lines are just required to get the code to compile.

答案1

得分: 229

现在我想要在启动父程序的终端窗口中看到子程序的标准输出,不需要使用管道或者goroutines,这个很简单。

func main() {
    // 将`ls`(以及它的参数)替换为更有趣的内容
    cmd := exec.Command("ls", "-l")
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr
    cmd.Run()
}
英文:

> Now I want to have the stdout of the child program in my terminal
> window where I started the parent program.

No need to mess with pipes or goroutines, this one is easy.

func main() {
    // Replace `ls` (and its arguments) with something more interesting
    cmd := exec.Command(&quot;ls&quot;, &quot;-l&quot;)
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr
    cmd.Run()
}

答案2

得分: 21

我相信如果你导入ioos并将这段代码替换为:

//fmt.Println(out)

使用以下代码:

go io.Copy(os.Stdout, out)

(参见io.Copy的文档os.Stdout的文档),它将实现你想要的功能。(免责声明:未经测试。)

顺便说一下,你可能还想捕获标准错误输出,可以使用与标准输出相同的方法,但使用cmd.StderrPipeos.Stderr

英文:

I believe that if you import io and os and replace this:

//fmt.Println(out)

with this:

go io.Copy(os.Stdout, out)

(see documentation for io.Copy and for os.Stdout), it will do what you want. (Disclaimer: not tested.)

By the way, you'll probably want to capture standard-error as well, by using the same approach as for standard-output, but with cmd.StderrPipe and os.Stderr.

答案3

得分: 15

对于那些不需要在循环中使用的人,但希望命令输出在终端中回显而不阻塞其他语句的人:

package main

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

func checkError(err error) {
	if err != nil {
		log.Fatalf("错误:%s", err)
	}
}

func main() {
	// 用更有趣的内容替换`ls`(及其参数)
	cmd := exec.Command("ls", "-l")

	// 创建类型为io.Reader的stdout、stderr流
	stdout, err := cmd.StdoutPipe()
	checkError(err)
	stderr, err := cmd.StderrPipe()
	checkError(err)

	// 启动命令
	err = cmd.Start()
	checkError(err)

	// 在我们的命令完成运行之前,不要让main()退出
	defer cmd.Wait() // 不阻塞

	// 非阻塞地将命令输出回显到终端
	go io.Copy(os.Stdout, stdout)
	go io.Copy(os.Stderr, stderr)

	// 我喜欢Go的简单并发 :-D
	fmt.Printf("在这里做其他事情!不需要等待。\n\n")
}
英文:

For those who don't need this in a loop, but would like the command output to echo into the terminal without having cmd.Wait() blocking other statements:

package main

import (
	&quot;fmt&quot;
	&quot;io&quot;
	&quot;log&quot;
	&quot;os&quot;
	&quot;os/exec&quot;
)

func checkError(err error) {
	if err != nil {
		log.Fatalf(&quot;Error: %s&quot;, err)
	}
}

func main() {
	// Replace `ls` (and its arguments) with something more interesting
	cmd := exec.Command(&quot;ls&quot;, &quot;-l&quot;)

	// 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&#39;t let main() exit before our command has finished running
	defer cmd.Wait()  // Doesn&#39;t block

	// Non-blockingly echo command output to terminal
	go io.Copy(os.Stdout, stdout)
	go io.Copy(os.Stderr, stderr)

	// I love Go&#39;s trivial concurrency :-D
	fmt.Printf(&quot;Do other stuff here! No need to wait.\n\n&quot;)
}

huangapple
  • 本文由 发表于 2012年1月16日 09:52:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/8875038.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定