如何捕获 stdout 输出并显示进度

How to capture stdout output but also show progress

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

我需要将它的标准输出打印传递给一个变量并打印它,但不是一次,直到它完成。
我需要一个无限循环的扫描仪,扫描标准输出并打印它,一旦功能完成,扫描仪也会完成。

我尝试使用 但它没有打印任何内容。
这是我尝试做的:

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, w, _ := 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)
    }
}