Go 从command exec实时捕获标准输出

Go 从command exec实时捕获标准输出,go,Go,我目前正在开发一个聊天机器人,它将执行命令。我希望它能够运行脚本并将脚本的stdout输出到聊天室中 我遇到的问题是,该函数收集脚本的所有标准输出,并在最后返回它们,我想尝试修改它以实时写入,但在这样做时遇到了问题 我认为这个问题可能涉及到的是,它只有一种方法可以将文本返回到聊天频道,那就是通过reboot的返回功能。但是,如果可能的话,我希望迭代exec命令并输出它 这是我的密码: func reboot(command *bot.Cmd) (string, error) { n :=

我目前正在开发一个聊天机器人,它将执行命令。我希望它能够运行脚本并将脚本的stdout输出到聊天室中

我遇到的问题是,该函数收集脚本的所有标准输出,并在最后返回它们,我想尝试修改它以实时写入,但在这样做时遇到了问题

我认为这个问题可能涉及到的是,它只有一种方法可以将文本返回到聊天频道,那就是通过reboot的返回功能。但是,如果可能的话,我希望迭代exec命令并输出它

这是我的密码:

func reboot(command *bot.Cmd) (string, error) {
    n := command.Args[0]
    // this return is what all gets sent into chat channel
    return runcommand(n), nil
  }


func runcommand(server string) string {
    cmd := exec.Command("/bin/bash", "-c", "python test.py %s", server)
    cmdOutput := &bytes.Buffer{}
    cmd.Stdout = cmdOutput
    err := cmd.Run()
    if err !=nil {
        os.Stderr.WriteString(err.Error())
    }
        return fmt.Sprintf(string(cmdOutput.Bytes()))
}

redis.log的实时命令管道。(您可以调用
bgsave
对其进行测试。)


我还没有找到解决你问题的办法,但我发现了一些奇怪的事情

我编写了三个版本的程序,以1秒的间隔重复输出一个短字符串,一个用Python,一个用C,一个用Go:

talker.py 空谈者 当我自己运行它们时(例如,
python./talker.py
),它们的工作方式似乎完全相同。但是,当我将输出传输到
cat
时,我看到了不同;C和Go版本立即将其输出显示在屏幕上,但Python版本并非如此。它的输出得到缓冲,在收集到足够的数据之前不会显示在屏幕上

我甚至尝试了一个简单的Go版本的
cat
,但这并没有改变行为:

package main

import (
        "io"
        "os"
)

func main() {
        io.Copy(os.Stdout, os.Stdin)
}

您需要更改
reboot
以启动启动命令的goroutine。您可以传递类似通道的内容,也可以传递一个
io.Reader
(例如:的输出)。这应该足以让你开始。我删除了我的答案,因为它不能解决你的问题。我尝试了几种方法来解决这个问题,但所有不直接写入标准输出的方法似乎都无法缓冲输出。请尝试运行
python-u test.py
。Python输出在默认情况下是缓冲的,在您的情况下可能会导致问题(特别是在您的输出很短的情况下)。@armanordokhani,这很有效!谢谢大家!@Blooze:不客气:)如果您的Python脚本很小,并且很容易在Go中重写,那么它可能可以做到这一点。使用
python-u talker.py
运行无缓冲版本。@Armanodookhani。谢谢,成功了。但是,当直接写入控制台时,为什么它看起来没有缓冲呢?Python是否检测到stdout是否连接到控制台?我不知道确切的答案。我认为,如果Python连接到tty(控制台),则Python行缓冲区标准输出是无效的。我认为C
printf
是一样的,您使用了不使用C缓冲系统的
write
syscall。Go在默认情况下选择在所有位置取消缓冲。
import time

while True:
        print("Now!")
        time.sleep(1)
#include <unistd.h>

main() {
        for(;;) {
                write(1, "Now!\n", 5);
                sleep(1);
        }
}
package main

import (
        "fmt"
        "time"
)

func main() {
        for {
                fmt.Println("Now!")
                time.Sleep(time.Second)
        }
}
package main

import (
        "io"
        "os"
)

func main() {
        io.Copy(os.Stdout, os.Stdin)
}