为了账号安全,请及时绑定邮箱和手机立即绑定

如何清除在 Golang 的 exec.Command 中设置为 StdOut

如何清除在 Golang 的 exec.Command 中设置为 StdOut

Go
HUX布斯 2022-05-10 14:12:28
我正在尝试在 GoLang 中编写一个命令行应用程序包装器,它公开一个 REST API 以与所述应用程序交互并显示其输出。基本上,当 REST API 服务器启动时,它应该启动一个持续运行的命令行应用程序(例如Powershell.exe),并且应该能够与应用程序交互并在通过 API 请求时显示其输出。到目前为止,服务器启动了,子进程也启动了,我可以向进程发出命令并检索它的输出。为了捕获进程的输出,我使用了一个bytes.Buffer,它附加到进程Stdout和Stderr。问题是该输出缓冲区似乎正在增长为无限,并且无法清除它。在该缓冲区上运行“ .Reset() ”似乎完全被忽略了,并且始终显示完整的缓冲输出。这是代码:package mainimport (    "bytes"    "fmt"    "log"    "net/http"    "os/exec")func main() {    var c = exec.Command("powershell.exe")    var b bytes.Buffer    c.Stdout = &b    c.Stderr = &b    stdin, err := c.StdinPipe()    if err != nil {        log.Fatal(err)    }    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {        fmt.Fprintf(w, "Do stuff")    })    http.HandleFunc("/clear", func(w http.ResponseWriter, r *http.Request) {        fmt.Fprintf(w, "Cleared")        b.Reset()    })    http.HandleFunc("/write", func(w http.ResponseWriter, r *http.Request) {        stdin.Write([]byte("echo hi\n"))        fmt.Fprintf(w, "OK")    })    http.HandleFunc("/show", func(w http.ResponseWriter, r *http.Request) {        fmt.Fprintf(w, string(b.Bytes()))    })    fmt.Println("SERVER 1 STARTING")    c.Start()    c.CombinedOutput()    http.ListenAndServe(":8081", nil)    fmt.Println("SERVER 1 STOPPED")}所以这里的预期行为是,当您调用“ /write ”时,它将在子应用程序中执行“echo hi”。“ /show ”将显示应用程序的输出缓冲区。“ /clear ”应该清除输出缓冲区,这样当你运行“ /write ”、“ /clear ”和“ /show ”时,应该显示一个空字符串。但在这种情况下,它会一直显示永远不会被清除的应用程序输出。有趣的是,如果我通过b.WriteString()手动写入缓冲区,然后执行b.Reset(),该内容会被删除,但不会删除命令行应用程序中的内容。当 bytes.Buffer 附加到 Stdout/Stderr 时,有什么方法可以正确清除它?或者,是否有某种方法可以将缓冲区限制为特定数量的行?
查看完整描述

1 回答

?
万千封印

TA贡献1891条经验 获得超3个赞

这似乎是一个同步问题。这不是网络服务器,而是 exec.Command 的工作方式以及缓冲区的共享方式。


这个程序可能有助于解释。它每秒运行 ping 并读取缓冲区,每次都尝试重置缓冲区。Ping 每秒都在写入缓冲区。


func main() {

    cmd := exec.Command("ping", "google.com")

    var buf bytes.Buffer

    cmd.Stdout = &buf


    err := cmd.Start()

    if err != nil {

        log.Fatal(err)

    }


    for i := 0; i < 3; i++ {

        time.Sleep(1 * time.Second)

        log.Println(buf.String())

        buf.Reset()

    }


    cmd.Process.Kill()

}

但是每次输出都是累加的,就好像对 buf.Reset() 的调用被忽略了一样:


$ go run main.go 

2020/01/28 22:05:25 PING google.com(syd09s13-in-x0e.1e100.net (2404:6800:4006:807::200e)) 56 data bytes

64 bytes from syd09s13-in-x0e.1e100.net (2404:6800:4006:807::200e): icmp_seq=1 ttl=50 time=50.3 ms


2020/01/28 22:05:26 PING google.com(syd09s13-in-x0e.1e100.net (2404:6800:4006:807::200e)) 56 data bytes

64 bytes from syd09s13-in-x0e.1e100.net (2404:6800:4006:807::200e): icmp_seq=1 ttl=50 time=50.3 ms

64 bytes from syd09s13-in-x0e.1e100.net (2404:6800:4006:807::200e): icmp_seq=2 ttl=50 time=52.0 ms


2020/01/28 22:05:27 PING google.com(syd09s13-in-x0e.1e100.net (2404:6800:4006:807::200e)) 56 data bytes

64 bytes from syd09s13-in-x0e.1e100.net (2404:6800:4006:807::200e): icmp_seq=1 ttl=50 time=50.3 ms

64 bytes from syd09s13-in-x0e.1e100.net (2404:6800:4006:807::200e): icmp_seq=2 ttl=50 time=52.0 ms

64 bytes from syd09s13-in-x0e.1e100.net (2404:6800:4006:807::200e): icmp_seq=3 ttl=50 time=57.1 ms

bytes.Buffer 可以替换为同步缓冲区,其中写入和读取由互斥锁保护。这有点简单,但例如:


type SyncBuf struct {

    mu  sync.Mutex

    buf bytes.Buffer

}


func (s *SyncBuf) Write(p []byte) (int, error) {

    s.mu.Lock()

    defer s.mu.Unlock()

    return s.buf.Write(p)

}


func (s *SyncBuf) Reset() {

    s.mu.Lock()

    defer s.mu.Unlock()

    s.buf.Reset()

}


func (s *SyncBuf) String() string {

    s.mu.Lock()

    defer s.mu.Unlock()

    return s.buf.String()

}

当缓冲区被替换时,输出行为符合预期,尊重 Reset() 调用:


$ go run main.go 

2020/01/28 22:07:03 PING google.com(syd09s13-in-x0e.1e100.net (2404:6800:4006:807::200e)) 56 data bytes

64 bytes from syd09s13-in-x0e.1e100.net (2404:6800:4006:807::200e): icmp_seq=1 ttl=50 time=50.4 ms


2020/01/28 22:07:04 64 bytes from syd09s13-in-x0e.1e100.net (2404:6800:4006:807::200e): icmp_seq=2 ttl=50 time=51.8 ms


2020/01/28 22:07:05 64 bytes from syd09s13-in-x0e.1e100.net (2404:6800:4006:807::200e): icmp_seq=3 ttl=50 time=50.8 ms


免责声明:这是作为插图发布的,它可能不是解决您问题的好方法。


查看完整回答
反对 回复 2022-05-10
  • 1 回答
  • 0 关注
  • 194 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号