如何捕获标准输出并显示进度

问题描述

我有一个名为print()的函数,该函数每2秒打印一次数字,该函数在goroutine中运行。

我需要将其stdout打印传递给一个变量并将其打印出来,但是直到完成时才打印一次。
我需要在无限循环中安装一些扫描仪,该扫描仪将扫描stdout并将其打印出来,一旦完成扫描仪的功能也将完成。

我尝试使用this answer,但是它不能打印任何内容。
这是我试图做的:

package main

import (
    "bufio"
    "fmt"
    "os"
    "sync"
    "time"
)


func print() {

    for i := 0; i < 50; i++ {
        time.Sleep(2 * time.Second)
        fmt.Printf("hello number: %d\n",i)
    }
}

func main() {
    old := os.Stdout // keep backup of the real stdout

    defer func() { os.Stdout = old }()
    r,w,_ := os.Pipe()
    os.Stdout = w

    go print()


    var wg sync.WaitGroup

    c := make(chan struct{})
    wg.Add(1)


    defer wg.Done()
    for {
        <-c
        scanner := bufio.NewScanner(r)
        for scanner.Scan() {
            m := scanner.Text()
            fmt.Println("output: " + m)
        }

    }

    c <- struct{}{}

    wg.Wait()
    fmt.Println("DONE")

}  

我还尝试使用io.Copy来读取这样的缓冲区,但是它也不起作用:

package main

import (
    "bytes"
    "fmt"
    "io"
    "os"
    "time"
)


func print() {

    for i := 0; i < 50; i++ {
        time.Sleep(2 * time.Second)
        fmt.Printf("hello number: %d\n",i)
    }
}

// https://blog.kowalczyk.info/article/wOYk/advanced-command-execution-in-go-with-osexec.html
func main() {
    old := os.Stdout // keep backup of the real stdout

    defer func() { os.Stdout = old }()
    r,_ := os.Pipe()
    os.Stdout = w

    go print()

    fmt.Println("DONE 1")
    outC := make(chan string)

    for {

        var buf bytes.Buffer
        io.Copy(&buf,r)
        outC <- buf.String()

        out := <-outC
        fmt.Println("output: " + out)
    }

    // back to normal state
    w.Close()


    fmt.Println("DONE")

}

解决方法

可以将print()作为“黑匣子”运行并捕获其输出,尽管这有点棘手并且在Go Playground上不起作用。

package main

import (
    "bufio"
    "fmt"
    "os"
    "runtime"
    "time"
)


func print() {
    for i := 0; i < 50; i++ {
        time.Sleep(100 * time.Millisecond)
        fmt.Printf("hello number: %d\n",i)
    }
}

func main() {

    var ttyName string
    if runtime.GOOS == "windows" {
    fmt.Println("*** Using `con`")
        ttyName = "con"
    } else {
    fmt.Println("*** Using `/dev/tty`")
        ttyName = "/dev/tty"
    }   

    f,err := os.OpenFile(ttyName,os.O_WRONLY,0644)
    if err != nil {
        panic(err)
    }
    defer f.Close()

    r,w,_ := os.Pipe()
    oldStdout := os.Stdout
    os.Stdout = w
    defer func() { 
        os.Stdout = oldStdout
        fmt.Println("*** DONE")
    }()

    fmt.Fprintln(f,"*** Stdout redirected")

    go func(){
       print()
       w.Close()
       r.Close()          
    }()

    c := make(chan struct{})
    go func(){c <- struct{}{}}()
    defer close(c)

    <-c
    scanner := bufio.NewScanner(r)
    for scanner.Scan() {
        m := scanner.Text()
        fmt.Fprintln(f,"output: " + m)
    }
}

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...