go - 如何在go中打印正在运行的子进程的实时输出?

Posted

技术标签:

【中文标题】go - 如何在go中打印正在运行的子进程的实时输出?【英文标题】:How to print the realtime output of running child process in go? 【发布时间】:2016-08-26 19:24:41 【问题描述】:

我有以下 bash 脚本 bash_loop.sh 打印 1 到 10 并在其间休眠 3 秒。

#!/bin/bash
# Basic while loop
counter=1
while [ $counter -le 10 ]
do
    echo $counter
    ((counter++))
   sleep 3 
done
echo All done

现在,我的 go 代码如下:

burstingScript := "bash_loop.sh"
cmd := exec.Command("/bin/sh", burstingScript)

var out bytes.Buffer
cmd.Stdout = &out
if err := cmd.Run(); err != nil 
    fmt.Println("An error has occurred..")
    log.Fatal(err)

fmt.Println(out.String())

但是,这只会在 cmd 运行 30 秒后 打印出所有内容,而不是在可用时打印。

所以我的问题是,如果我可以打印每个数字 bash 脚本仍在运行,而不是在 bash 脚本完成执行后将所有内容一起打印。

P.S.1:在实际用例中,我必须实时处理 bash 脚本的输出,而不是简单地将内容打印到 os.Stdout,所以我想知道是否有任何命令 poll() 接口或等效项去吧。

P.S.2:在实际用例中,我想一发现有趣的消息就与子进程分离。例如,在我读到 3 之后,我希望我的函数立即返回 3 而不再等待其余的输出,尽管我仍然希望子进程(bash 脚本)本身能够启动并运行。

P.S.3:在 python 中,我会做这样的事情

cmd = "./bash_loop.sh"
p = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE)

result = 
while True:
    out = p.stdout.readline()
    if out == '' and p.poll() != None:
        break
    if out != '':
        #process(out)
        sys.stdout.write(out)
        sys.stdout.flush()

P.S.4:现在我已经进化了我的 go sn-p 来跟随。如果我在命令运行完成之前返回,孩子会变成僵尸吗?

burstingScript := path.Join(rootDir, "bash_loop.sh")
cmd := exec.Command("/bin/sh", burstingScript)

stdout, _ := cmd.StdoutPipe()
cmd.Start()
scanner := bufio.NewScanner(stdout)
for scanner.Scan() 
    m := scanner.Text()
    fmt.Println(m)
    //if m=="3" 
    //  return process(m)
    //

cmd.Wait()

【问题讨论】:

Streaming commands output progress 的相关/可能重复。 @icza 很棒的指针。我添加了 P.S.2,而不是等待整个 Cmd 完成,我希望我的函数在读取后立即返回有趣的输出,而不会终止正在运行的进程。 re P.S.4,是的,你需要调用wait,所以在调用cmd.Wait()之前不要返回。 【参考方案1】:

将命令输出设置为标准输出:

cmd.Stdout = os.Stdout

【讨论】:

我实际上想嗅探 bash 脚本的输出并在将其打印到 os.Stdout 之前进行一些处理。 下次一定要在你的问题中提到你想做的每一件事,以避免问这些:xyproblem.info @cookieisaac:那为什么不使用StdOutPipe?

以上是关于go - 如何在go中打印正在运行的子进程的实时输出?的主要内容,如果未能解决你的问题,请参考以下文章

实时打印使用 Python 中的子进程启动的 bash 命令的结果

如何使用“测试”包在 Go 测试中打印?

重定向Go中子进程的stdout管道

Go 执行命令行并实时打印输出

如何在 Debian 中将简单的 Go 服务器作为守护进程运行?

如何使用 Go 漂亮地打印 JSON?