猿问

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

我有一个如下函数来执行命令并向stdout(终端)显示输出:


package main


// https://blog.kowalczyk.info/article/wOYk/advanced-command-execution-in-go-with-osexec.html


import (

    "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/bash


declare -a arr=("frontend" "backend" "middleware" "apigateway")

for service in "${arr[@]}"

do

  sleep 1

  echo $service-prod-secret.yaml

done

现在,我只在命令运行时输出输出到操作系统。Stdout(终端),但我想让这个输出逐行推送到一些地方(EX:socket)以显示执行命令的进度,因为我有一个命令需要很长时间才能完成,很难只看到白屏而不知道命令的进度。


输出:


frontend-prod-secret.yaml

backend-prod-secret.yaml

middleware-prod-secret.yaml

apigateway-prod-secret.yaml


out:

frontend-prod-secret.yaml

backend-prod-secret.yaml

middleware-prod-secret.yaml

apigateway-prod-secret.yaml

我需要等待命令完成才能获得输出,但这需要很长时间。


如何逐行(实时)引用输出以推送到所需的某些位置?


萧十郎
浏览 117回答 2
2回答

梵蒂冈之花

您应该侦听 stdout 和 stderr 缓冲区,并在它们获取新数据时打印它们。您可以使用扫描仪扫描缓冲区:package mainimport (    "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.yamlbackend-prod-secret.yamlmiddleware-prod-secret.yamlapigateway-prod-secret.yaml

斯蒂芬大帝

操作系统。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 stringstype 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.StdOutchat, err := ChatConnect()cmd.Stdout = chat
随时随地看视频慕课网APP

相关分类

Go
我要回答