Go 如何捕获标准输出,同时显示进度
我有一个名为Go 如何捕获标准输出,同时显示进度,go,pipe,output,stdout,goroutine,Go,Pipe,Output,Stdout,Goroutine,我有一个名为print()的函数,它每2秒打印一次数字,这个函数在goroutine中运行 我需要将它的标准输出传递给一个变量并打印它,但不能一次,直到它完成。 我需要在一个无限循环中有一个扫描仪,它将扫描标准输出并打印它,一旦功能完成,扫描仪也将完成 我试图使用它,但它不打印任何内容。 这就是我试图做的: package main import ( "bufio" "fmt" "os" "s
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")
}
可以将
print()
作为“黑盒”运行并捕获其输出,尽管这有点棘手,在围棋场上不起作用
主程序包
进口(
“布菲奥”
“fmt”
“操作系统”
“运行时”
“时间”
)
func print(){
对于i:=0;i<50;i++{
时间。睡眠(100*时间。毫秒)
fmt.Printf(“你好号码:%d\n”,i)
}
}
func main(){
var ttyName字符串
如果runtime.GOOS==“windows”{
fmt.Println(“***使用'con`”)
ttyName=“con”
}否则{
fmt.Println(“***使用`/dev/tty`”)
ttyName=“/dev/tty”
}
f、 err:=os.OpenFile(ttyName,os.O_WRONLY,0644)
如果错误!=零{
恐慌(错误)
}
延迟f.关闭()
r、 w,u:=os.Pipe()
oldStdout:=os.Stdout
os.Stdout=w
延迟函数(){
os.Stdout=旧Stdout
格式打印项次(“***完成”)
}()
fmt.Fprintln(f,“***标准输出已重定向”)
go func(){
打印()
w、 关闭()
r、 关闭()
}()
c:=make(chan结构{})
go func(){c我不知道您想做什么,但将os.Stdout分配给其他对象是错误的。如果您想在标准输出以外的其他地方打印,请使用而不是Println。您的第一个代码片段几乎没有致命问题。例如,您尝试使用管道和扫描仪捕获fmt.Printf
-这可能会起作用,但然后您将捕获的结果发送到fmt.Println()
,后者也会打印到Stdout
,并且Stdout已经重定向到Pipe()
,因此结果不会打印到控制台(正如您可能期望的那样),而是再次转到Scanner
。还有其他问题,但这个问题应该首先解决。@maxim_ge我将fmt.Println
更改为fmt.Printf
,它仍然不起作用。我试图将fmt.Printf
更改为fmt.Println
,但它也不起作用:(@Peter I将fmt.Println
更改为fmt.Fprintf(w,“输出:+m”)
但它仍然不打印任何内容。但我需要从管道的标准输出读取它,这就是问题所在。基本上,我试图做的是在函数仍在进行时读取函数的打印。@E235我会像这样重构您的代码太棒了!它可以工作:)谢谢!感谢您理解使用print()的重要性
作为blackbox,它对我很重要。仅供参考,它在Windows上不起作用,只在Linux上起作用,但现在它对我来说已经足够了。我需要做的下一件事是看看如何在打印()时捕获打印
已经完成,但我会自己尝试,如果我有问题,我会打开一个新问题。我注意到,当我删除time.Sleep(100*time.millis秒)
时,它不会打印,是否可以让扫描仪等待打印()
function finish?@E235实际上,您必须等待扫描仪完成读取。最好的方法是以某种方式刷新标准输出,但我不知道如何进行。作为一种解决方法,您可以在print()
之后立即添加对time.Sleep()
的调用。这将给扫描仪一些时间
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")
}