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

获取 os.exec 的输出以显示执行命令的进度

获取 os.exec 的输出以显示执行命令的进度

Go
萧十郎 2022-08-01 15:18:19
我有一个如下函数来执行命令并向stdout(终端)显示输出:package main// https://blog.kowalczyk.info/article/wOYk/advanced-command-execution-in-go-with-osexec.htmlimport (    "bytes"    "io"    "fmt"    "log"    "os"    "os/exec")func main() {    cmd := exec.Command("./test.sh")    var stdoutBuf, stderrBuf bytes.Buffer    cmd.Stdout = io.MultiWriter(os.Stdout, &stdoutBuf)    cmd.Stderr = io.MultiWriter(os.Stderr, &stderrBuf)    err := cmd.Run()    if err != nil {        log.Fatalf("cmd.Run() failed with %s\n", err)    }    outStr, errStr := string(stdoutBuf.Bytes()), string(stderrBuf.Bytes())    fmt.Printf("\nout:\n%s\nerr:\n%s\n", outStr, errStr)}这是要测试的 bash 脚本:#!/bin/bashdeclare -a arr=("frontend" "backend" "middleware" "apigateway")for service in "${arr[@]}"do  sleep 1  echo $service-prod-secret.yamldone现在,我只在命令运行时输出输出到操作系统。Stdout(终端),但我想让这个输出逐行推送到一些地方(EX:socket)以显示执行命令的进度,因为我有一个命令需要很长时间才能完成,很难只看到白屏而不知道命令的进度。输出:frontend-prod-secret.yamlbackend-prod-secret.yamlmiddleware-prod-secret.yamlapigateway-prod-secret.yamlout:frontend-prod-secret.yamlbackend-prod-secret.yamlmiddleware-prod-secret.yamlapigateway-prod-secret.yaml我需要等待命令完成才能获得输出,但这需要很长时间。如何逐行(实时)引用输出以推送到所需的某些位置?
查看完整描述

2 回答

?
梵蒂冈之花

TA贡献1900条经验 获得超5个赞

您应该侦听 stdout 和 stderr 缓冲区,并在它们获取新数据时打印它们。


您可以使用扫描仪扫描缓冲区:


package main


import (

    "bufio"

    "fmt"

    "io"

    "os/exec"

)


func main() {

    cmd := exec.Command("test.sh")

    

    stdout, _ := cmd.StdoutPipe()

    stderr, _ := cmd.StderrPipe()

    _ = cmd.Start()


    scanner := bufio.NewScanner(io.MultiReader(stdout, stderr))

    scanner.Split(bufio.ScanWords)

    for scanner.Scan() {

        m := scanner.Text()

        fmt.Println(m)

    }

    _ = cmd.Wait()

}


打印数据在缓冲区中显示的状态(因此行与行之间存在休眠状态)


frontend-prod-secret.yaml

backend-prod-secret.yaml

middleware-prod-secret.yaml

apigateway-prod-secret.yaml


查看完整回答
反对 回复 2022-08-01
?
斯蒂芬大帝

TA贡献1827条经验 获得超8个赞

操作系统。StdOut正在寻找一个具有方法的接口,在编写其输出时,它将调用此方法。Write


我想逐行获取此输出并推送到某些位置(例如:套接字)


让我举个例子


import (

    "flag"

    "github.com/gorilla/websocket"

    "net/url"

)


var addr = flag.String("addr", "localhost:12345", "http service address")


// this function allows transmitting of output

// and command as chat message strings

type CommandChat struct {

    Conn *websocket.Conn

}


func ChatConnect() (c *CommandChat, err error) {

    u := url.URL{Scheme: "ws", Host: *addr, Path: "/echo"}

    conn, _, err := websocket.DefaultDialer.Dial(u.String(), nil)

    c = &CommandChat{Conn: conn}

    return

}


func (c *CommandChat) Write(input []byte) (n int, err error) {

    err = c.Conn.WriteMessage(websocket.TextMessage, input)

    return

}

func (c *CommandChat) Rx(resp []byte) (err error) {

    return

}

func (c *CommandChat) Close() (err error) { return }

现在您可以分配给CommandChatos.StdOut


chat, err := ChatConnect()

cmd.Stdout = chat


查看完整回答
反对 回复 2022-08-01
  • 2 回答
  • 0 关注
  • 116 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信